How FadCam Manages Video Segments and Auto-Splitting: Architecture Explained
FadCam stores every editable video portion as a Clip object inside a Timeline, using a robust splitAt() method for manual editing and a size-monitoring RecordingService for automatic segment creation when file limits are reached.
FadCam (anonfaded/FadCam) is an open-source Android camera application that handles long recordings through intelligent segment management. Understanding how it structures video segments and performs both manual and automatic splitting is essential for developers looking to implement similar timeline-based editing or automatic file rotation features. The architecture centers on two core classes—Clip and Timeline—working alongside recording services that monitor file size thresholds.
Clip Representation: The Atomic Video Segment
Every visual element on FadCam’s editing timeline maps 1‑to‑1 to a Clip object defined in app/src/main/java/com/fadcam/ui/faditor/model/Clip.java. This class encapsulates not just the media reference, but all transformation properties that persist when a segment is split.
public class Clip {
@NonNull private final String id; // Unique identifier (UUID)
@NonNull private final Uri sourceUri; // Original video file path
private long inPointMs; // Trim start in milliseconds
private long outPointMs; // Trim end in milliseconds
private long sourceDurationMs; // Original untrimmed length
private float speed = 1.0f; // Playback speed multiplier
private float volume = 1.0f; // Audio level (0.0 to 1.0)
private int rotation = 0; // Rotation in degrees
private boolean flipHorizontal = false; // Mirror transform
private RectF cropRect = new RectF(0, 0, 1, 1); // Normalized crop box
// Clone constructor preserves all effects during splitting
public Clip(@NonNull Clip other) {
this.id = UUID.randomUUID().toString();
this.sourceUri = other.sourceUri;
this.inPointMs = other.inPointMs;
this.outPointMs = other.outPointMs;
this.sourceDurationMs = other.sourceDurationMs;
this.speed = other.speed;
this.volume = other.volume;
this.rotation = other.rotation;
this.flipHorizontal = other.flipHorizontal;
this.cropRect = new RectF(other.cropRect);
}
}
When FadCam converts a Clip for playback, it generates a Media3 MediaItem with a ClippingConfiguration set to the inPointMs and outPointMs. Because the clone constructor copies all effect parameters (speed, volume, rotation, etc.), splitting a clip automatically preserves the user’s creative adjustments across both resulting segments.
Timeline: The Central Segment Manager
The Timeline class in app/src/main/java/com/fadcam/ui/faditor/model/Timeline.java serves as the single source of truth for video composition. It maintains an ordered list of clips and provides the primary API for segment manipulation.
Key responsibilities of the Timeline include:
- Ordered storage:
private final List<Clip> clipsmaintains chronological sequence - Duration calculation:
getTotalDurationMs()aggregates the duration of all clips, accounting for speed changes - Structural operations:
addClip(),removeClip(),swapClips(), andmoveClip()handle reordering - Splitting logic:
splitAt(int clipIndex, long splitPointMs)executes the core segmentation algorithm
Manual Splitting Logic via splitAt()
Manual splitting occurs when a user taps the split button in the editor. The Timeline.splitAt() method enforces a 100-millisecond minimum distance from clip edges to avoid creating micro-segments, then performs a non-destructive split by cloning the original clip and adjusting its boundary points.
public int splitAt(int clipIndex, long splitPointMs) {
// Validate index bounds
if (clipIndex < 0 || clipIndex >= clips.size()) {
return -1;
}
Clip original = clips.get(clipIndex);
// Enforce minimum 100ms buffer from edges
long minSplitMs = original.getInPointMs() + 100;
long maxSplitMs = original.getOutPointMs() - 100;
if (splitPointMs < minSplitMs || splitPointMs > maxSplitMs) {
return -1; // Split point too close to edge
}
// Create two clips inheriting all effects from original
Clip clipA = new Clip(original);
clipA.setOutPointMs(splitPointMs);
Clip clipB = new Clip(original);
clipB.setInPointMs(splitPointMs);
// Atomic replacement: remove original, insert A and B
clips.remove(clipIndex);
clips.add(clipIndex, clipB); // Add second part first (higher index)
clips.add(clipIndex, clipA); // Add first part at original index
return clipIndex; // Return index of clipA (first part)
}
This approach ensures that metadata like speed adjustments or crop rectangles remain consistent across the split point, providing a seamless editing experience where segments behave as a continuous whole during playback.
UI Integration in FaditorEditorActivity
The editor interface bridges user input and the Timeline API through FaditorEditorActivity.java. When the user positions the playhead and triggers a split, the activity calculates the absolute time position and invokes the Timeline method.
private void splitAtPlayhead() {
long currentPositionMs = player.getCurrentPosition();
int selectedClipIndex = timelineView.getCurrentClipIndex();
// Convert player position to clip-local time
long clipStartTime = timeline.getClipStartTimeMs(selectedClipIndex);
long absoluteSplitMs = currentPositionMs - clipStartTime;
int newIndex = timeline.splitAt(selectedClipIndex, absoluteSplitMs);
if (newIndex < 0) {
Toast.makeText(this, R.string.faditor_split_error, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, R.string.faditor_split_success, Toast.LENGTH_SHORT).show();
refreshTimelineView();
updatePlayerClippingConfiguration();
}
}
The UI enforces visual feedback through Toast messages defined in string resources, distinguishing between successful splits and validation errors (such as attempting to split within 100ms of a clip boundary).
Auto-Splitting Implementation
FadCam’s auto-splitting feature automatically segments long recordings into multiple files when they approach a user-defined size limit (defaulting to 2GB, with options up to 4GB). This prevents filesystem limitations and ensures compatibility with older storage formats that impose file size caps.
Configuration Layer
The feature is controlled via value_video_split_enabled in the settings layout app/src/main/res/layout/fragment_settings_video.xml. When enabled, the recording service receives the size threshold (in bytes) through shared preferences.
RecordingService Logic
The automatic splitting logic resides in RecordingService.java within the app/src/main/java/com/fadcam/service/ package. During active recording, the service monitors the output file size after each write cycle:
private void monitorRecordingSize() {
if (!videoSplittingEnabled) return;
long maxBytes = splitSizeLimitBytes; // From user settings (2GB = 2_147_483_648L)
File currentFile = recorder.getCurrentOutputFile();
if (currentFile.length() >= maxBytes) {
// Finalize current segment
String finalizedPath = stopCurrentRecording();
// Create new clip entry in Timeline for the completed segment
Clip completedClip = new Clip(finalizedPath);
timeline.addClip(completedClip);
// Start fresh recording seamlessly
startNewRecordingSegment();
// The new recording automatically generates the next Clip on completion
}
}
When the size threshold triggers, the service:
- Finalizes the current MediaRecorder instance and closes the file
- Creates a new
Clipobject referencing the completed file, adding it to the Timeline withinPointMsat 0 andoutPointMsat the actual duration - Immediately initializes a new
MediaRecordertargeting a fresh filename (typically timestamped or indexed) - Continues capture without user-visible interruption
This process creates a sequence of Clip entries that appear as continuous content in the editor, despite residing in separate physical files on disk.
Interaction Between Manual and Automatic Splitting
Both splitting modalities converge on the same data model, ensuring architectural consistency:
- Manual splits (editor UI) use
Timeline.splitAt()to subdivide existing clips during post-production - Auto-splits (recording service) append new
Clipinstances to the Timeline when file size limits trigger during capture
Because both paths generate standard Clip objects with identical property inheritance, the export engine (ExportService) processes auto-split and manually-split segments through the same pipeline—applying transitions, mixing audio, and rendering effects without distinguishing the split origin.
Summary
- Clip Architecture: Each segment is a
Clipobject inClip.javastoring trim points, effects, and source URI, with a copy constructor that preserves all properties during splits. - Timeline Management: The
Timelineclass maintains an orderedList<Clip>and providessplitAt()with 100ms boundary validation to prevent micro-segments. - Manual Splitting:
FaditorEditorActivity.javatranslates playhead positions intosplitAt()calls, with immediate UI feedback via Toast messages. - Auto-Splitting:
RecordingService.javamonitors file size againstvalue_video_split_enabledpreferences, automatically finalizing and restarting recordings at 2GB (or user-defined) thresholds while appending new clips to the Timeline. - Unified Model: Both splitting methods produce identical
Clipobjects, allowing seamless editing and export regardless of whether segmentation occurred during recording or post-processing.
Frequently Asked Questions
How does FadCam preserve video effects when splitting a clip?
When Timeline.splitAt() executes, it invokes the Clip copy constructor (new Clip(original)) to create two new instances. This constructor duplicates all effect parameters—including speed, volume, rotation, flipHorizontal, and cropRect—so both resulting segments inherit the exact same visual and audio adjustments as the original.
What is the minimum duration required between split points?
The splitAt() method enforces a 100-millisecond buffer from both the inPointMs and outPointMs of the original clip. If the requested split point falls within 100ms of either edge, the method returns -1 and the UI displays R.string.faditor_split_error, preventing the creation of unusable micro-segments.
Where is the auto-split file size limit configured?
Users enable automatic splitting via Settings → Video → "Enable Video Splitting", which controls the boolean preference value_video_split_enabled. The threshold size (default 2GB, maximum 4GB) is passed to RecordingService.java, where the monitorRecordingSize() method compares currentFile.length() against this limit to trigger segment rotation.
Can auto-split recordings be edited the same way as manually split videos?
Yes. Both manual and automatic splits produce identical Clip objects stored in the Timeline. Auto-split clips reference separate physical files but expose the same properties (inPointMs, outPointMs, effects) as manually split clips, allowing the FaditorEditorActivity to perform drag-and-drop reordering, trimming, and effect adjustments without distinguishing the split origin.
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 →