Skip to main content
View as Markdown

Video Generation - Avatar Videos

Video Generation​

Generate the Video​

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

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​

# 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:

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.