16 KiB
Timeline Editing Guide
VideoDB provides a non-destructive timeline editor for composing videos from multiple assets, adding text and image overlays, mixing audio tracks, and trimming clips — all server-side without re-encoding or local tools. Use this for trimming, combining clips, overlaying audio/music on video, adding subtitles, and layering text or images.
Prerequisites
Videos, audio, and images must be uploaded to a collection before they can be used as timeline assets. For caption overlays, the video must also be indexed for spoken words.
Core Concepts
Timeline
A Timeline is a virtual composition layer. Assets are placed on it either inline (sequentially on the main track) or as overlays (layered at a specific timestamp). Nothing modifies the original media; the final stream is compiled on demand.
from videodb.timeline import Timeline
timeline = Timeline(conn)
Assets
Every element on a timeline is an asset. VideoDB provides five asset types:
| Asset | Import | Primary Use |
|---|---|---|
VideoAsset |
from videodb.asset import VideoAsset |
Video clips (trim, sequencing) |
AudioAsset |
from videodb.asset import AudioAsset |
Music, SFX, narration |
ImageAsset |
from videodb.asset import ImageAsset |
Logos, thumbnails, overlays |
TextAsset |
from videodb.asset import TextAsset, TextStyle |
Titles, captions, lower-thirds |
CaptionAsset |
from videodb.editor import CaptionAsset |
Auto-rendered subtitles (Editor API) |
Building a Timeline
Add Video Clips Inline
Inline assets play one after another on the main video track. The add_inline method only accepts VideoAsset:
from videodb.asset import VideoAsset
video_a = coll.get_video(video_id_a)
video_b = coll.get_video(video_id_b)
timeline = Timeline(conn)
timeline.add_inline(VideoAsset(asset_id=video_a.id))
timeline.add_inline(VideoAsset(asset_id=video_b.id))
stream_url = timeline.generate_stream()
Trim / Sub-clip
Use start and end on a VideoAsset to extract a portion:
# Take only seconds 10–30 from the source video
clip = VideoAsset(asset_id=video.id, start=10, end=30)
timeline.add_inline(clip)
VideoAsset Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
asset_id |
str |
required | Video media ID |
start |
float |
0 |
Trim start (seconds) |
end |
float|None |
None |
Trim end (None = full) |
Warning: The SDK does not validate negative timestamps. Passing
start=-5is silently accepted but produces broken or unexpected output. Always ensurestart >= 0,start < end, andend <= video.lengthbefore creating aVideoAsset.
Text Overlays
Add titles, lower-thirds, or captions at any point on the timeline:
from videodb.asset import TextAsset, TextStyle
title = TextAsset(
text="Welcome to the Demo",
duration=5,
style=TextStyle(
fontsize=36,
fontcolor="white",
boxcolor="black",
alpha=0.8,
font="Sans",
),
)
# Overlay the title at the very start (t=0)
timeline.add_overlay(0, title)
TextStyle Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
fontsize |
int |
24 |
Font size in pixels |
fontcolor |
str |
"black" |
CSS colour name or hex |
fontcolor_expr |
str |
"" |
Dynamic font colour expression |
alpha |
float |
1.0 |
Text opacity (0.0–1.0) |
font |
str |
"Sans" |
Font family |
box |
bool |
True |
Enable background box |
boxcolor |
str |
"white" |
Background box colour |
boxborderw |
str |
"10" |
Box border width |
boxw |
int |
0 |
Box width override |
boxh |
int |
0 |
Box height override |
line_spacing |
int |
0 |
Line spacing |
text_align |
str |
"T" |
Text alignment within the box |
y_align |
str |
"text" |
Vertical alignment reference |
borderw |
int |
0 |
Text border width |
bordercolor |
str |
"black" |
Text border colour |
expansion |
str |
"normal" |
Text expansion mode |
basetime |
int |
0 |
Base time for time-based expressions |
fix_bounds |
bool |
False |
Fix text bounds |
text_shaping |
bool |
True |
Enable text shaping |
shadowcolor |
str |
"black" |
Shadow colour |
shadowx |
int |
0 |
Shadow X offset |
shadowy |
int |
0 |
Shadow Y offset |
tabsize |
int |
4 |
Tab size in spaces |
x |
str |
"(main_w-text_w)/2" |
Horizontal position expression |
y |
str |
"(main_h-text_h)/2" |
Vertical position expression |
Audio Overlays
Layer background music, sound effects, or voiceover on top of the video track:
from videodb.asset import AudioAsset
music = coll.get_audio(music_id)
audio_layer = AudioAsset(
asset_id=music.id,
disable_other_tracks=False,
fade_in_duration=2,
fade_out_duration=2,
)
# Start the music at t=0, overlaid on the video track
timeline.add_overlay(0, audio_layer)
AudioAsset Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
asset_id |
str |
required | Audio media ID |
start |
float |
0 |
Trim start (seconds) |
end |
float|None |
None |
Trim end (None = full) |
disable_other_tracks |
bool |
True |
When True, mutes other audio tracks |
fade_in_duration |
float |
0 |
Fade-in seconds (max 5) |
fade_out_duration |
float |
0 |
Fade-out seconds (max 5) |
Image Overlays
Add logos, watermarks, or generated images as overlays:
from videodb.asset import ImageAsset
logo = coll.get_image(logo_id)
logo_overlay = ImageAsset(
asset_id=logo.id,
duration=10,
width=120,
height=60,
x=20,
y=20,
)
timeline.add_overlay(0, logo_overlay)
ImageAsset Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
asset_id |
str |
required | Image media ID |
width |
int|str |
100 |
Display width |
height |
int|str |
100 |
Display height |
x |
int |
80 |
Horizontal position (px from left) |
y |
int |
20 |
Vertical position (px from top) |
duration |
float|None |
None |
Display duration (seconds) |
Caption Overlays
There are two ways to add captions to video.
Method 1: Subtitle Workflow (simplest)
Use video.add_subtitle() to burn subtitles directly onto a video stream. This uses the videodb.timeline.Timeline internally:
from videodb import SubtitleStyle
# Video must have spoken words indexed first (force=True skips if already done)
video.index_spoken_words(force=True)
# Add subtitles with default styling
stream_url = video.add_subtitle()
# Or customise the subtitle style
stream_url = video.add_subtitle(style=SubtitleStyle(
font_name="Arial",
font_size=22,
primary_colour="&H00FFFFFF",
bold=True,
))
Method 2: Editor API (advanced)
The Editor API (videodb.editor) provides a track-based composition system with CaptionAsset, Clip, Track, and its own Timeline. This is a separate API from the videodb.timeline.Timeline used above.
from videodb.editor import (
CaptionAsset,
Clip,
Track,
Timeline as EditorTimeline,
FontStyling,
BorderAndShadow,
Positioning,
CaptionAnimation,
)
# Video must have spoken words indexed first (force=True skips if already done)
video.index_spoken_words(force=True)
# Create a caption asset
caption = CaptionAsset(
src="auto",
font=FontStyling(name="Clear Sans", size=30),
primary_color="&H00FFFFFF",
back_color="&H00000000",
border=BorderAndShadow(outline=1),
position=Positioning(margin_v=30),
animation=CaptionAnimation.box_highlight,
)
# Build an editor timeline with tracks and clips
editor_tl = EditorTimeline(conn)
track = Track()
track.add_clip(start=0, clip=Clip(asset=caption, duration=video.length))
editor_tl.add_track(track)
stream_url = editor_tl.generate_stream()
CaptionAsset Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
src |
str |
"auto" |
Caption source ("auto" or base64 ASS string) |
font |
FontStyling|None |
FontStyling() |
Font styling (name, size, bold, italic, etc.) |
primary_color |
str |
"&H00FFFFFF" |
Primary text colour (ASS format) |
secondary_color |
str |
"&H000000FF" |
Secondary text colour (ASS format) |
back_color |
str |
"&H00000000" |
Background colour (ASS format) |
border |
BorderAndShadow|None |
BorderAndShadow() |
Border and shadow styling |
position |
Positioning|None |
Positioning() |
Caption alignment and margins |
animation |
CaptionAnimation|None |
None |
Animation effect (e.g., box_highlight, reveal, karaoke) |
Compiling & Streaming
After assembling a timeline, compile it into a streamable URL. Streams are generated instantly - no render wait times.
stream_url = timeline.generate_stream()
print(f"Stream: {stream_url}")
For more streaming options (segment streams, search-to-stream, audio playback), see streaming.md.
Complete Workflow Examples
Highlight Reel with Title Card
import videodb
from videodb import SearchType
from videodb.exceptions import InvalidRequestError
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle
conn = videodb.connect()
coll = conn.get_collection()
video = coll.get_video("your-video-id")
# 1. Search for key moments
video.index_spoken_words(force=True)
try:
results = video.search("product announcement", search_type=SearchType.semantic)
shots = results.get_shots()
except InvalidRequestError as exc:
if "No results found" in str(exc):
shots = []
else:
raise
# 2. Build timeline
timeline = Timeline(conn)
# Title card
title = TextAsset(
text="Product Launch Highlights",
duration=4,
style=TextStyle(fontsize=48, fontcolor="white", boxcolor="#1a1a2e", alpha=0.95),
)
timeline.add_overlay(0, title)
# Append each matching clip
for shot in shots:
asset = VideoAsset(asset_id=shot.video_id, start=shot.start, end=shot.end)
timeline.add_inline(asset)
# 3. Generate stream
stream_url = timeline.generate_stream()
print(f"Highlight reel: {stream_url}")
Logo Overlay with Background Music
import videodb
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, AudioAsset, ImageAsset
conn = videodb.connect()
coll = conn.get_collection()
main_video = coll.get_video(main_video_id)
music = coll.get_audio(music_id)
logo = coll.get_image(logo_id)
timeline = Timeline(conn)
# Main video track
timeline.add_inline(VideoAsset(asset_id=main_video.id))
# Background music — disable_other_tracks=False to mix with video audio
timeline.add_overlay(
0,
AudioAsset(asset_id=music.id, disable_other_tracks=False, fade_in_duration=3),
)
# Logo in top-right corner for first 10 seconds
timeline.add_overlay(
0,
ImageAsset(asset_id=logo.id, duration=10, x=1140, y=20, width=120, height=60),
)
stream_url = timeline.generate_stream()
print(f"Final video: {stream_url}")
Multi-Clip Montage from Multiple Videos
import videodb
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle
conn = videodb.connect()
coll = conn.get_collection()
clips = [
{"video_id": "vid_001", "start": 5, "end": 15, "label": "Scene 1"},
{"video_id": "vid_002", "start": 0, "end": 20, "label": "Scene 2"},
{"video_id": "vid_003", "start": 30, "end": 45, "label": "Scene 3"},
]
timeline = Timeline(conn)
timeline_offset = 0.0
for clip in clips:
# Add a label as an overlay on each clip
label = TextAsset(
text=clip["label"],
duration=2,
style=TextStyle(fontsize=32, fontcolor="white", boxcolor="#333333"),
)
timeline.add_inline(
VideoAsset(asset_id=clip["video_id"], start=clip["start"], end=clip["end"])
)
timeline.add_overlay(timeline_offset, label)
timeline_offset += clip["end"] - clip["start"]
stream_url = timeline.generate_stream()
print(f"Montage: {stream_url}")
Two Timeline APIs
VideoDB has two separate timeline systems. They are not interchangeable:
videodb.timeline.Timeline |
videodb.editor.Timeline (Editor API) |
|
|---|---|---|
| Import | from videodb.timeline import Timeline |
from videodb.editor import Timeline as EditorTimeline |
| Assets | VideoAsset, AudioAsset, ImageAsset, TextAsset |
CaptionAsset, Clip, Track |
| Methods | add_inline(), add_overlay() |
add_track() with Track / Clip |
| Best for | Video composition, overlays, multi-clip editing | Caption/subtitle styling with animations |
Do not mix assets from one API into the other. CaptionAsset only works with the Editor API. VideoAsset / AudioAsset / ImageAsset / TextAsset only work with videodb.timeline.Timeline.
Limitations & Constraints
The timeline editor is designed for non-destructive linear composition. The following operations are not supported:
Not Possible
| Limitation | Detail |
|---|---|
| No transitions or effects | No crossfades, wipes, dissolves, or transitions between clips. All cuts are hard cuts. |
| No video-on-video (picture-in-picture) | add_inline() only accepts VideoAsset. You cannot overlay one video stream on top of another. Image overlays can approximate static PiP but not live video. |
| No speed or playback control | No slow-motion, fast-forward, reverse playback, or time remapping. VideoAsset has no speed parameter. |
| No crop, zoom, or pan | Cannot crop a region of a video frame, apply zoom effects, or pan across a frame. video.reframe() is for aspect-ratio conversion only. |
| No video filters or color grading | No brightness, contrast, saturation, hue, or color correction adjustments. |
| No animated text | TextAsset is static for its full duration. No fade-in/out, movement, or animation. For animated captions, use CaptionAsset with the Editor API. |
| No mixed text styling | A single TextAsset has one TextStyle. Cannot mix bold, italic, or colors within a single text block. |
| No blank or solid-color clips | Cannot create a solid color frame, black screen, or standalone title card. Text and image overlays require a VideoAsset beneath them on the inline track. |
| No audio volume control | AudioAsset has no volume parameter. Audio is either full volume or muted via disable_other_tracks. Cannot mix at a reduced level. |
| No keyframe animation | Cannot change overlay properties over time (e.g., move an image from position A to B). |
Constraints
| Constraint | Detail |
|---|---|
| Audio fade max 5 seconds | fade_in_duration and fade_out_duration are capped at 5 seconds each. |
| Overlay positioning is absolute | Overlays use absolute timestamps from the timeline start. Rearranging inline clips does not move their overlays. |
| Inline track is video only | add_inline() only accepts VideoAsset. Audio, image, and text must use add_overlay(). |
| No overlay-to-clip binding | Overlays are placed at a fixed timeline timestamp. There is no way to attach an overlay to a specific inline clip so it moves with it. |
Tips
- Non-destructive: Timelines never modify source media. You can create multiple timelines from the same assets.
- Overlay stacking: Multiple overlays can start at the same timestamp. Audio overlays mix together; image/text overlays layer in add-order.
- Inline is VideoAsset only:
add_inline()only acceptsVideoAsset. Useadd_overlay()forAudioAsset,ImageAsset, andTextAsset. - Trim precision:
start/endonVideoAssetandAudioAssetare in seconds. - Muting video audio: Set
disable_other_tracks=TrueonAudioAssetto mute the original video audio when overlaying music or narration. - Fade limits:
fade_in_durationandfade_out_durationonAudioAssethave a maximum of 5 seconds. - Generated media: Use
coll.generate_music(),coll.generate_sound_effect(),coll.generate_voice(), andcoll.generate_image()to create media that can be used as timeline assets immediately.