Signed-off-by: ZhengWG <zwg0606@gmail.com> Signed-off-by: wuli666 <421774554@qq.com> Co-authored-by: wuli666 <421774554@qq.com>
298 lines
12 KiB
Markdown
298 lines
12 KiB
Markdown
# Videos API
|
|
|
|
vLLM-Omni provides an OpenAI-compatible video generation API for diffusion
|
|
video models. The API supports asynchronous video jobs through `/v1/videos` and
|
|
a synchronous benchmark-oriented endpoint through `/v1/videos/sync`.
|
|
|
|
Each server instance runs a single model specified at startup with
|
|
`vllm serve <model> --omni`.
|
|
|
|
## Quick Start
|
|
|
|
### Start the Server
|
|
|
|
```bash
|
|
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers --omni --port 8091
|
|
```
|
|
|
|
### Create a Video Job
|
|
|
|
```bash
|
|
create_response=$(curl -s http://localhost:8091/v1/videos \
|
|
-F "prompt=A cinematic tracking shot of a mountain lake at sunrise" \
|
|
-F "width=1280" \
|
|
-F "height=720" \
|
|
-F "num_frames=80" \
|
|
-F "fps=16" \
|
|
-F "num_inference_steps=40")
|
|
|
|
video_id=$(echo "${create_response}" | jq -r '.id')
|
|
```
|
|
|
|
### Poll and Download
|
|
|
|
```bash
|
|
curl -s "http://localhost:8091/v1/videos/${video_id}" | jq .
|
|
curl -L "http://localhost:8091/v1/videos/${video_id}/content" -o output.mp4
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
| ---------- | -------- | ------------- |
|
|
| `/v1/videos` | `POST` | Create an asynchronous video generation job |
|
|
| `/v1/videos/sync` | `POST` | Generate a video synchronously and return raw video bytes |
|
|
| `/v1/videos/{video_id}` | `GET` | Retrieve job status and metadata |
|
|
| `/v1/videos` | `GET` | List stored video jobs |
|
|
| `/v1/videos/{video_id}/content` | `GET` | Download generated video content |
|
|
| `/v1/videos/{video_id}` | `DELETE` | Delete a video job and stored output |
|
|
|
|
### Request Parameters
|
|
|
|
`POST /v1/videos` and `POST /v1/videos/sync` accept `multipart/form-data`.
|
|
|
|
#### OpenAI-style fields
|
|
|
|
| Parameter | Type | Default | Description |
|
|
| ----------- | ------ | --------- | ------------- |
|
|
| `prompt` | string | **required** | Text prompt for video generation |
|
|
| `model` | string | server's model | Optional model name |
|
|
| `seconds` | string | null | Requested clip duration in seconds |
|
|
| `size` | string | null | Requested output size in `WIDTHxHEIGHT` format |
|
|
| `user` | string | null | Optional user identifier |
|
|
|
|
#### vLLM-Omni extension fields
|
|
|
|
| Parameter | Type | Default | Description |
|
|
| ----------- | ------ | --------- | ------------- |
|
|
| `input_reference` | file | null | Uploaded reference image or video for image-to-video/video-to-video requests |
|
|
| `control_reference` | file | null | Optional uploaded image/video control, up to 512 MiB, for models that declare control-upload support |
|
|
| `control_type` | string | null | Model control name associated with `control_reference`; currently Cosmos3 supports `edge`, `blur`, `depth`, `seg`, and `wsm` |
|
|
| `image_reference` | string | null | JSON-encoded reference image payload; do not combine with `input_reference` or `video_reference` |
|
|
| `video_reference` | string | null | JSON-encoded reference video payload; do not combine with `input_reference` or `image_reference` |
|
|
| `audio_reference` | string | null | JSON-encoded audio reference for speech-to-video: `{"audio_url": "..."}` — supports HTTP(s) URLs or base64 data URLs |
|
|
| `width` | integer | model default | Output video width |
|
|
| `height` | integer | model default | Output video height |
|
|
| `num_frames` | integer | 1 | Number of generated frames |
|
|
| `fps` | integer | model default | Output frames per second |
|
|
| `num_inference_steps` | integer | model default | Number of diffusion steps |
|
|
| `guidance_scale` | number | null | CFG guidance scale for the low-noise stage |
|
|
| `guidance_scale_2` | number | null | CFG guidance scale for the high-noise stage |
|
|
| `boundary_ratio` | number | null | Boundary split ratio for multi-stage denoising |
|
|
| `flow_shift` | number | null | Scheduler flow-shift value |
|
|
| `true_cfg_scale` | number | null | True CFG scale when supported by the model |
|
|
| `seed` | integer | null | Random seed for reproducibility |
|
|
| `generate_sound` | boolean | false | Request model-generated audio for video models that support sound generation |
|
|
| `sound_duration` | number | null | Duration in seconds for generated audio; defaults to generated video duration |
|
|
| `negative_prompt` | string | null | Text describing what to avoid in the generated video |
|
|
| `enable_frame_interpolation` | boolean | null | Enable post-generation frame interpolation |
|
|
| `frame_interpolation_exp` | integer | null | Interpolation exponent; `1=2x`, `2=4x`, and so on |
|
|
| `frame_interpolation_scale` | number | null | RIFE inference scale |
|
|
| `frame_interpolation_model_path` | string | null | Local path or Hugging Face repo for the interpolation model |
|
|
| `lora` | string | null | JSON-encoded LoRA configuration object |
|
|
| `extra_params` | string | null | JSON-encoded object for additional model-specific parameters |
|
|
|
|
### Create Response
|
|
|
|
`POST /v1/videos` returns a job record:
|
|
|
|
```json
|
|
{
|
|
"id": "video-123",
|
|
"status": "queued",
|
|
"created_at": 1701234567
|
|
}
|
|
```
|
|
|
|
The final content is available from `/v1/videos/{video_id}/content` after the
|
|
job status becomes `completed`.
|
|
|
|
`queued` means the request is still waiting for diffusion scheduler admission.
|
|
The status changes to `in_progress` when the scheduler first selects the
|
|
request for execution.
|
|
|
|
`DELETE /v1/videos/{video_id}` issues a bounded engine abort
|
|
(`VLLM_OMNI_ABORT_TIMEOUT`, default 2s), then cancels the frontend
|
|
task. Cancellation cleanup is also bounded and best-effort: it confirms
|
|
the abort was queued, and the current request batch may still drain.
|
|
The job is then re-read so a completed save is not orphaned.
|
|
|
|
### Synchronous Response
|
|
|
|
`POST /v1/videos/sync` blocks until generation finishes and returns raw video
|
|
bytes. It is useful for benchmarks and simple scripts that do not need job
|
|
storage or polling.
|
|
|
|
## Examples
|
|
|
|
### Image-to-Video
|
|
|
|
```bash
|
|
curl -s http://localhost:8091/v1/videos \
|
|
-F "prompt=animate this image with subtle camera movement" \
|
|
-F "input_reference=@input.png" \
|
|
-F "width=1280" \
|
|
-F "height=720" \
|
|
-F "num_frames=80" \
|
|
-F "fps=16"
|
|
```
|
|
|
|
### Video-to-Video
|
|
|
|
For models that support video conditioning, upload the reference video with
|
|
`input_reference`:
|
|
|
|
```bash
|
|
curl -s http://localhost:8091/v1/videos \
|
|
-F "prompt=continue this motion with consistent subjects and lighting" \
|
|
-F "input_reference=@input.mp4;type=video/mp4" \
|
|
-F "width=1280" \
|
|
-F "height=720" \
|
|
-F "num_frames=80" \
|
|
-F "fps=16"
|
|
```
|
|
|
|
You can also pass a JSON-safe video URL or `data:video/...;base64,...` payload
|
|
through `video_reference`. Do not send `video_reference` together with
|
|
`input_reference` or `image_reference`.
|
|
|
|
```bash
|
|
curl -s http://localhost:8091/v1/videos \
|
|
-F "prompt=continue this motion with consistent subjects and lighting" \
|
|
-F 'video_reference={"video_url":"https://example.com/input.mp4"}' \
|
|
-F "width=1280" \
|
|
-F "height=720" \
|
|
-F "num_frames=80" \
|
|
-F "fps=16"
|
|
```
|
|
|
|
JSON references currently support `image_url`/`video_url`; `file_id` references
|
|
are not implemented yet. Models may expose additional V2V controls through
|
|
`extra_params`. For example, Cosmos3 supports
|
|
`condition_frame_indexes_vision` and `condition_video_keep` to select which
|
|
decoded reference frames are used as clean conditioning. Cosmos3 transfer mode
|
|
also accepts `edge`, `blur`, `depth`, `seg`, or `wsm` control hints. Each hint
|
|
may specify its own `control_path` and `control_weight`. Request-level transfer
|
|
options include
|
|
`control_guidance`, `control_guidance_interval`,
|
|
`emphasize_control_in_prompt`, `num_video_frames_per_chunk`,
|
|
`num_conditional_frames`, `show_control_condition`, and `show_input`. Transfer
|
|
uses its transfer-specific system prompt and, by default, appends a
|
|
control-adherence directive to the positive prompt. It adds duration/FPS and
|
|
resolution metadata to both CFG branches but does not add a negative prompt
|
|
automatically. The Cosmos3 recipe includes an optional reference negative
|
|
prompt and shows how to pass it. Set `emphasize_control_in_prompt`,
|
|
`use_duration_template`, or `use_resolution_template` to `false` to disable the
|
|
corresponding addition. `negative_metadata_mode` accepts `same`, `inverse`, or
|
|
`none` and defaults to `same` for transfer. See the Cosmos3 recipe for complete
|
|
examples.
|
|
|
|
A client that cannot place the control on the server filesystem can upload one
|
|
control with `control_reference` and identify it with `control_type`. The API
|
|
streams the upload to request-scoped storage, supplies its path to the model,
|
|
and removes it after synchronous or asynchronous generation completes. Other
|
|
options for the selected control can remain in `extra_params`; do not also set
|
|
`control` or `control_path` there. Uploads larger than 512 MiB are rejected.
|
|
|
|
```bash
|
|
curl -s http://localhost:8091/v1/videos/sync \
|
|
-F "prompt=Preserve the scene while following the world-state control" \
|
|
-F "input_reference=@input.mp4;type=video/mp4" \
|
|
-F "control_reference=@wsm.mp4;type=video/mp4" \
|
|
-F "control_type=wsm" \
|
|
-F 'extra_params={"wsm":{"control_weight":1.0}}' \
|
|
-o output.mp4
|
|
```
|
|
|
|
HTTP redirects for `image_reference.image_url` follow vLLM's
|
|
`VLLM_MEDIA_URL_ALLOW_REDIRECTS` setting. Before starting the server, set it to
|
|
`1` (the default) to allow redirects or `0` to reject them. A redirect target
|
|
can differ from the original host, and vLLM-Omni does not yet fully implement
|
|
upstream vLLM's media URL allowlist protection. Deployments should therefore
|
|
treat remote media URLs as untrusted and choose this setting as part of their
|
|
URL access policy.
|
|
|
|
### Speech-to-Video
|
|
|
|
For models that support audio-driven generation (e.g., Wan2.2-S2V), pass both
|
|
an image reference and an audio reference. The `audio_reference` field accepts a
|
|
JSON string with `audio_url` pointing to an HTTP(s) URL or base64 data URL.
|
|
|
|
```bash
|
|
curl -s http://localhost:8091/v1/videos \
|
|
-F "prompt=A person singing" \
|
|
-F 'image_reference={"image_url": "https://example.com/face.png"}' \
|
|
-F 'audio_reference={"audio_url": "https://example.com/speech.mp3"}' \
|
|
-F "width=832" \
|
|
-F "height=480" \
|
|
-F "num_inference_steps=40" \
|
|
-F "guidance_scale=4.5" \
|
|
-F "fps=16"
|
|
```
|
|
|
|
### Synchronous Generation
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8091/v1/videos/sync \
|
|
-F "prompt=A small robot walking through a neon city" \
|
|
-F "width=854" \
|
|
-F "height=480" \
|
|
-F "num_frames=80" \
|
|
-F "fps=16" \
|
|
-o output.mp4
|
|
```
|
|
|
|
## Output Encoding
|
|
|
|
These `extra_params` control how the server turns decoded frames into MP4 bytes.
|
|
|
|
| Field | Type | Default | Description |
|
|
| --- | --- | --- | --- |
|
|
| `preencode_mp4` | boolean | false | Encode the MP4 on the worker while the VAE is still decoding, instead of after the full video is materialized |
|
|
| `video_codec_options` | object | null | Encoder options passed through to the H.264 encoder, such as `{"preset": "ultrafast", "threads": "0"}` |
|
|
|
|
With `preencode_mp4` enabled, each committed VAE chunk leaves the accelerator and
|
|
is encoded while later chunks are still decoding, so host transfer and CPU
|
|
encoding overlap the remaining decode instead of following it. The response is
|
|
unchanged: the same complete MP4, byte-for-byte equivalent frames.
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8091/v1/videos/sync \
|
|
-F "prompt=A small robot walking through a neon city" \
|
|
-F 'extra_params={"preencode_mp4": true, "video_codec_options": {"preset": "ultrafast"}}' \
|
|
-o output.mp4
|
|
```
|
|
|
|
`preencode_mp4` applies to the complete-MP4 response paths only. The
|
|
`/v1/realtime/video` WebSocket endpoint rejects it, because that path already
|
|
overlaps encoding through its own incremental fragmented-MP4 encoder.
|
|
|
|
Support is per model: MiniMax-H3 implements it, and other models ignore the flag
|
|
and take the full-decode path.
|
|
|
|
## Storage
|
|
|
|
Set `VLLM_OMNI_SERVER_STORAGE__PATH` to control where asynchronous video outputs are
|
|
stored:
|
|
|
|
```bash
|
|
export VLLM_OMNI_SERVER_STORAGE__PATH=/var/tmp/vllm-omni-videos
|
|
```
|
|
|
|
> `VLLM_OMNI_STORAGE_PATH` is deprecated and will be removed in a future release;
|
|
> use `VLLM_OMNI_SERVER_STORAGE__PATH` instead.
|
|
|
|
## Model-Specific Examples
|
|
|
|
For complete text-to-video, image-to-video, and model-specific video-to-video
|
|
walkthroughs, see:
|
|
|
|
- [Text-to-Video](../user_guide/examples/online_serving/text_to_video.md)
|
|
- [Image-to-Video](../user_guide/examples/online_serving/image_to_video.md)
|
|
- [Speech-to-Video](../user_guide/examples/online_serving/speech_to_video.md)
|
|
for Wan2.2-S2V audio-driven lip-sync generation
|
|
- [Cosmos3 recipes](https://github.com/vllm-project/vllm-omni/blob/main/recipes/cosmos3/Cosmos3-Nano.md)
|
|
for model-specific video-to-video examples and conditioning controls
|