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.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)
results = video.search("product announcement", search_type=SearchType.semantic)
shots = results.get_shots() # may be empty if no results
# 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.