How to Generate SRT Subtitles with Offset Timelines After Segment Concatenation in Video-Use
Video-use accumulates segment durations into a running seg_offset variable to shift transcript timestamps onto the final concatenated timeline, outputting a master SRT file via the build_master_srt function in helpers/render.py.
The browser-use/video-use repository provides a complete pipeline for extracting video segments, concatenating them, and generating accurate SRT subtitles that reflect the final output timeline. When multiple clips are stitched together, the subtitles must account for the cumulative duration of preceding segments to maintain synchronization. This article explains the exact mechanism used to calculate these offsets and produce the master subtitle file.
The Subtitle Generation Pipeline
The entire process is orchestrated by the build_master_srt function located in helpers/render.py at line 315. This routine is invoked automatically when you pass the --build-subtitles flag to the render script. It processes an Edit Decision List (EDL) to determine which segments appear in the final video and adjusts all subtitle timestamps accordingly.
Parsing the Edit Decision List (EDL)
The function iterates over the ranges array in the EDL JSON file. Each range represents one extracted clip with a specific start and end time from a source video:
for r in edl["ranges"]:
src_name = r["source"]
seg_start = float(r["start"])
seg_end = float(r["end"])
seg_duration = seg_end - seg_start
During this iteration, the code maintains a seg_offset variable initialized to 0.0 at line 326. This accumulator tracks the total duration of all previously processed segments.
Accumulating Segment Offsets
The offset accumulation happens immediately after processing each range. Even if a segment lacks a transcript, the offset increases to ensure subsequent subtitles align correctly with the concatenated timeline. As implemented in the source code at line 326, the offset preserves the exact position of each clip within the final output.
Loading and Filtering Transcripts
For each EDL range, the system attempts to load a transcript JSON file from edit_dir/transcripts/<source>.json. If the file is missing, the range is skipped, but seg_offset is still incremented to maintain timeline integrity (line 335).
When a transcript exists, the helper function _words_in_range (line 300) scans the word-level timing data to select only those utterances that fall within the current segment's boundaries:
words = _words_in_range(transcript, seg_start, seg_end)
Chunking and Timestamp Shifting
Selected words are grouped into caption chunks of at most two words, breaking early on punctuation marks defined by PUNCT_BREAK (line 443). This creates readable captions that align with natural speech pauses.
The critical offset calculation occurs at line 562. For each word chunk, the code first determines the local time relative to the source segment, then shifts it by the cumulative seg_offset:
out_start = max(0.0, local_start - seg_start) + seg_offset
out_end = max(0.0, local_end - seg_start) + seg_offset
This math ensures that out_start and out_end represent absolute positions on the final concatenated video timeline, not the original source timestamps.
Formatting and Writing the SRT File
The helper _srt_timestamp (line 292) converts floating-point second counts into the standard HH:MM:SS,mmm format required by the SRT specification. After processing all EDL ranges, the complete subtitle entries are sorted by start time and written to edit_dir/master.srt (line 776).
Code Implementation Details
The offset logic relies on precise arithmetic to handle edge cases such as segments starting mid-sentence. The max(0.0, ...) guard prevents negative timestamps while the seg_offset accumulator ensures continuity across clip boundaries.
Here is the core timestamp transformation as implemented in the source:
# seg_offset accumulates the duration of all previous segments
seg_offset = 0.0
for r in edl["ranges"]:
# ... load transcript and get words ...
for chunk in word_chunks:
local_start = chunk[0]["start"]
local_end = chunk[-1]["end"]
# Shift from source-relative to output-relative time
out_start = max(0.0, local_start - seg_start) + seg_offset
out_end = max(0.0, local_end - seg_start) + seg_offset
# Convert to SRT format
start_ts = _srt_timestamp(out_start)
end_ts = _srt_timestamp(out_end)
The SUB_FORCE_STYLE constant defined at line 41 in helpers/render.py specifies the default subtitle appearance (font, size, margins) when the SRT is later burned into the video using ffmpeg.
Command-Line Usage
To generate the offset-adjusted subtitle file during rendering, invoke the script with the --build-subtitles flag:
# Render video and generate master.srt with corrected timelines
python helpers/render.py edl.json -o final.mp4 --build-subtitles
This command processes the EDL, calculates all offsets, and deposits master.srt in the edit_dir directory.
To inspect the generated file:
1
00:00:00,000 --> 00:00:02,400
THIS IS
2
00:00:02,400 --> 00:00:04,800
AN EXAMPLE
3
00:00:04,800 --> 00:00:05,600
OF CAPTION
Notice that the timestamps reflect the concatenated timeline—the second cue starts at 00:00:02,400 because the first segment had a duration of 2.4 seconds.
To burn these subtitles into the final video with the forced style:
ffmpeg -i base.mp4 \
-vf "subtitles='edit/master.srt':force_style='FontName=Helvetica,FontSize=18,Bold=1,MarginV=90'" \
-c:a copy final_with_subs.mp4
Summary
- Offset Accumulation: The
seg_offsetvariable tracks cumulative segment duration to align subtitles with the concatenated output timeline. - Core Function:
build_master_srtinhelpers/render.py(line 315) orchestrates the entire pipeline. - Timestamp Math: Each cue's start and end times are shifted by
seg_offsetafter being normalized to the segment start (line 562). - Input Data: Per-source transcripts are loaded from
edit_dir/transcripts/<source>.jsonand filtered by the_words_in_rangehelper. - Output: A single
master.srtfile containing chronologically sorted, offset-corrected captions ready for ffmpeg overlay.
Frequently Asked Questions
What happens if a video segment has no transcript file?
If the expected JSON transcript is missing from edit_dir/transcripts/, the range is skipped without generating subtitles, but seg_offset is still increased by the segment duration (line 335). This ensures that subsequent subtitles remain synchronized with the video timeline even when gaps exist in the transcript coverage.
How does the system handle words that span across segment boundaries?
The _words_in_range function (line 300) selects words whose temporal intervals overlap the segment's start and end times. When a word is split across segments, it appears only in the segment where its start time falls, ensuring no duplicate captions while maintaining the offset continuity through the seg_offset accumulator.
Can I adjust the number of words per caption line?
Yes, the chunking logic in helpers/render.py groups words into captions of at most two words by default (line 443). You can modify the chunking parameters or the PUNCT_BREAK logic in the source to allow longer lines, though this requires editing the _chunk_words implementation directly.
Why are my subtitles appearing at the wrong time in the final video?
Incorrect timing usually indicates that seg_offset was not properly accumulated, which happens if the EDL ranges are processed out of order or if segment durations are miscalculated. Ensure that your edl.json contains correct start and end values for each range, and verify that --build-subtitles was used during rendering to trigger the offset calculation logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →