How to Build a Java Sub Editor: A Step-by-Step GuideCreating a subtitle (sub) editor in Java is an excellent project that covers GUI design, file parsing and writing, timecode handling, text processing, and optional multimedia synchronization for previewing. This guide walks through the design and implementation of a desktop Java subtitle editor that supports common formats (SRT, VTT), basic editing features, timing adjustments, and playback preview using a media library. Code samples, design decisions, and extension ideas are included so you can build a reliable, user-friendly tool.
Overview and core features
A basic Java subtitle editor should provide:
- Open and save SRT and VTT subtitle files.
- Visual timeline and per-line editing of text and timecodes.
- Shift and stretch timing for selected lines or the whole file.
- Search, replace, spellcheck, and basic formatting.
- Preview video/audio with subtitle overlay (optional).
- Undo/redo and autosave.
Architecture and technology choices
- GUI: JavaFX (recommended) or Swing. JavaFX offers modern controls, CSS styling, and media playback support.
- Parsing: Custom parser or use libraries (e.g., com.github.bsideup:subtitles for parsing; or write your own for learning).
- Media playback: JavaFX MediaPlayer for common formats, or VLCJ (VLC bindings) for broader codec support.
- Data model: MVC/MVVM pattern — a SubtitleDocument model containing a list of SubtitleCue objects (startTime, endTime, text, id).
- Persistence: Plain text read/write for SRT/VTT; consider export to other formats (ASS) later.
Data model
Define a simple cue model:
public class SubtitleCue { private Duration start; private Duration end; private String text; private int id; // constructors, getters, setters, toString }
Use a document to hold cues and operations:
public class SubtitleDocument { private List<SubtitleCue> cues = new ArrayList<>(); private Path filePath; // methods: load(Path), save(Path), addCue, removeCue, shift( Duration ), stretch( double ), sort(), validate() }
Parsing and writing SRT (step-by-step)
SRT format basics:
- Numeric cue index
- Timecode: “HH:MM:SS,mmm –> HH:MM:SS,mmm”
- One or more text lines
- Blank line
Parsing approach:
- Read file into lines.
- Iterate, parse index, parse time range with regex, collect text lines until blank line.
- Convert timecode to Duration.
Example parsing snippet:
private static final Pattern SRT_TIME = Pattern.compile( "(\d{2}):(\d{2}):(\d{2}),(\d{3})\s*-->\s*(\d{2}):(\d{2}):(\d{2}),(\d{3})" ); public static SubtitleDocument loadSrt(Path path) throws IOException { List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8); SubtitleDocument doc = new SubtitleDocument(); int i = 0; while (i < lines.size()) { String indexLine = lines.get(i++).trim(); if (indexLine.isEmpty()) continue; // parse index int index = Integer.parseInt(indexLine); String timeLine = lines.get(i++).trim(); Matcher m = SRT_TIME.matcher(timeLine); if (!m.matches()) throw new IOException("Invalid timecode at line " + i); Duration start = toDuration(m, 1); Duration end = toDuration(m, 5); StringBuilder text = new StringBuilder(); while (i < lines.size() && !(lines.get(i).trim().isEmpty())) { if (text.length() > 0) text.append(" "); text.append(lines.get(i++)); } SubtitleCue cue = new SubtitleCue(start, end, text.toString(), index); doc.addCue(cue); } return doc; }
Write SRT by formatting cues back to the SRT timecode string.
GUI design (JavaFX)
Main layout:
- Left: File & timeline controls (open, save, shift, stretch, undo/redo).
- Center: TableView of cues (columns: ID, start, end, text) editable inline.
- Bottom: Video preview and timeline scrubber (if media available).
- Right: Properties panel for selected cue and spellcheck suggestions.
TableView example column setup:
TableColumn<SubtitleCue, Integer> idCol = new TableColumn<>("ID"); TableColumn<SubtitleCue, String> startCol = new TableColumn<>("Start"); TableColumn<SubtitleCue, String> endCol = new TableColumn<>("End"); TableColumn<SubtitleCue, String> textCol = new TableColumn<>("Text"); textCol.setCellFactory(TextFieldTableCell.forTableColumn());
Bind start/end columns to formatted String properties; editing should parse back into Duration (with validation).
Editing features
- Inline edit with validation: ensure start < end, no negative durations.
- Merge/split cues: splitting a cue at a specific character/time creates two cues with adjusted times.
- Timing adjustments:
- Shift: add/subtract a Duration to selected cues or whole document.
- Stretch: apply linear transform t’ = a * t + b to shift and scale (useful for resync).
- Overlap detection: after edits, run validation to detect overlapping cues and highlight them.
- Auto-numbering: reindex cues on save or on demand.
Stretch example:
public void stretch(double scale, Duration offset) { for (SubtitleCue c : cues) { c.setStart(Duration.ofMillis((long)(c.getStart().toMillis() * scale) + offset.toMillis())); c.setEnd(Duration.ofMillis((long)(c.getEnd().toMillis() * scale) + offset.toMillis())); } sort(); }
Video preview & synchronization
Use JavaFX MediaPlayer for simple playback:
- Load video file with Media and display in MediaView.
- Use a timeline listener to find active cue(s) at current playback position and render text overlay.
Basic example:
Media media = new Media(videoFile.toUri().toString()); MediaPlayer player = new MediaPlayer(media); MediaView view = new MediaView(player); player.currentTimeProperty().addListener((obs, old, cur) -> { Duration pos = cur; List<SubtitleCue> active = doc.getCuesAt(pos); overlayLabel.setText(active.stream().map(SubtitleCue::getText).collect(Collectors.joining(" "))); });
For robust codec support, integrate VLCJ (requires native VLC).
Undo/Redo and autosave
- Use Command pattern: each user action (edit text, change time, add/remove) is a Command with execute/undo.
- Maintain two stacks: undoStack, redoStack.
- Autosave: periodically serialize the document to a temp file; restore on next start if temp exists.
Internationalization and encoding
- Always read/write subtitle files using UTF-8 by default; allow user to change encoding if needed.
- Support RTL languages and diacritics; ensure font fallback in UI and overlay.
Testing and validation
- Unit tests for parsers: valid and malformed cases (missing indices, bad timecodes).
- Integration tests for load -> edit -> save cycle (compare normalized output).
- Visual/manual tests with multiple video files and formats.
Packaging and deployment
- Package as a self-contained application using jpackage (creates native installers) or bundle with a fat JAR via jlink/jpackage.
- Include required native libraries if using VLCJ.
Extensions and advanced features
- Support ASS/SSA with styling and positioning.
- Machine translation / auto-translate lines (call external services).
- Speech-to-text generation of draft subtitles (integrate Whisper-like models).
- Batch processing for timing adjustments across many files.
- Collaboration features (track changes, comments) with a server backend.
Example roadmap (milestones)
- Basic SRT load/save and TableView editor.
- Timing shift/stretch, validation, autosave.
- Undo/redo, merge/split, search/replace.
- Video preview with overlay sync.
- Support VTT and ASS; package app.
Sample minimal project layout
src/
- model/SubtitleCue.java
- model/SubtitleDocument.java
- io/SrtParser.java
- ui/MainApp.java
- ui/EditorController.java
- media/MediaPreview.java
- util/Commands.java
Conclusion
Building a Java subtitle editor is an achievable project that touches useful areas of application development: parsing, GUI, media handling, and user experience. Start small (SRT support, table editor) then progressively add features (timing tools, preview, formats). The architecture outlined here—JavaFX UI, clear data model, parser + writer, and optional media integration—gives a solid foundation you can extend for production use.
Leave a Reply