---
title: Video Generation
url: https://docs.kaltura.com/docs/conversational-agents/avatar-videos/video-generation
---

## Video Generation

### Generate the Video

Once scenes are ready (status is `draft` or `composed`), generate the final video:

```bash
curl -s -X POST "$AVATAR_API/video/generate" \
  -H "Authorization: Bearer $KS" \
  -H "Content-Type: application/json" \
  -d "{ \"id\": \"$VIDEO_ID\" }"
```

The generate action:
1. Transitions the video status to `generating`  
2. **Scene generation (parallel):** For each scene, generates TTS audio, then renders the avatar video. Full-screen and b-roll scenes are rendered by separate backend services  
3. **Aggregation:** Stitches all scene videos together. For b-roll scenes, the background video is clipped at the specified `startTime` for the narration duration, and the avatar is composited as an overlay with green-screen replacement. All scenes are normalized to 1920×1080  
4. Uploads the final video as a Kaltura media entry  
5. Sets `entryId` on the video and transitions to `ready`  

**Response:** Returns the video with status `generating`. Poll `video.get` until status becomes `ready`.

### Poll for Completion

```bash
# Poll every 10 seconds until status is "ready" or an error
while true; do
  RESULT=$(curl -s -X POST "$AVATAR_API/video/get" \
    -H "Authorization: Bearer $KS" \
    -H "Content-Type: application/json" \
    -d "{ \"id\": \"$VIDEO_ID\" }")

  STATUS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
  echo "Status: $STATUS"

  if [ "$STATUS" = "ready" ]; then
    ENTRY_ID=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('entryId',''))")
    echo "Generated entry: $ENTRY_ID"
    break
  elif [ "$STATUS" = "generate-error" ]; then
    echo "Generation failed"
    break
  fi

  sleep 10
done
```

Generation time depends on the number of scenes, narration length, and current queue depth. Simple videos (1–3 full-screen scenes) typically complete in 2–5 minutes. Complex videos with many b-roll scenes can take 10–30 minutes or more. The process has two phases: scene generation (TTS + avatar rendering for each scene, runs in parallel) and aggregation (stitching scenes together with b-roll compositing). The `entryId` field appears on the video object once aggregation begins — its presence indicates scene generation succeeded and stitching is underway.

**Generation error diagnostics:**  
When generation fails, the status becomes `generate-error`. The API response includes only the status change — diagnose using the checklist below. Common causes:
- **Narration too short** — Ensure each scene produces at least ~1.5 seconds of TTS audio (~4+ words). Use one complete sentence per scene  
- **B-roll frame rate** — Confirm b-roll entries use 25 or 30 fps (see b-roll requirements in section 6)  
- **Rendering service busy** — Retry after a few minutes if all content checks pass  

**Isolating the cause:** Start by testing a minimal 1-scene full-screen video. If that succeeds, the issue is b-roll-specific — verify b-roll entry frame rate is 25 or 30 fps and confirm the entry is in `status=2` (Ready). If the 1-scene test also produces `generate-error`, verify narration length (~4+ words per scene) or retry later for a transient service issue.

### Reset Status After Error

If composition or generation fails, reset the status to allow editing and retrying:

```bash
curl -s -X POST "$AVATAR_API/video/resetStatus" \
  -H "Authorization: Bearer $KS" \
  -H "Content-Type: application/json" \
  -d "{ \"id\": \"$VIDEO_ID\" }"
```

**Reset behavior:**
- `compose-error` → resets to `draft`  
- `generate-error` → resets to `composed` (if previously composed) or `draft`  
- Other statuses → returns `CANNOT_RESET_STATUS`  

After resetting, you can modify scenes via `video/update` and call `video/generate` again. The previous `entryId` (if any) is retained — a new generation overwrites it with a fresh entry.
