|
| 1 | +## 🎬 VideoEditor (R&D Project) |
| 2 | + |
| 3 | +VideoEditor is an **R&D / educational** iOS video editing app experiment targeting iOS 16.0+. The goal is to explore modern Swift, UIKit, Concurrency and media technologies (e.g. AVFoundation, CoreImage, CoreVideo) with a **sustainable and testable** architecture. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Project vision |
| 8 | +- **Simplify AVKit Usage**: While compositing videos (AVVideoTrackComposition) |
| 9 | +- **1**: Make stil images handled like a video or audio track. |
| 10 | +- **2**: Simplify overlay media item usages with tracks. |
| 11 | +- **3**: Fix video stoping when audio shorter than video track. |
| 12 | +- **4**: Use core image downsampling for each frame to avoid memory pressures. |
| 13 | +- **Modularity**: Clear separation of UI, Domain, and Data layers. |
| 14 | +- **Testability**: Dependencies are injected via DI. |
| 15 | +- **Simplicity**: KISS principle; avoid unnecessary abstraction. |
| 16 | +- **UIKit-first**: Screens are built with programmatic UIKit + Auto Layout. |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Requirements |
| 21 | + |
| 22 | +- **Xcode**: 26.3 |
| 23 | +- **iOS Deployment Target**: 16.0+ |
| 24 | +- **Language**: Swift 5.5+ |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## Preview engine: from `EditingProject` to playback |
| 29 | + |
| 30 | +The editor preview is **not** a raw file player. It rebuilds an **AVFoundation composition** from the current project state whenever you load or press play. |
| 31 | + |
| 32 | +### Pipeline overview |
| 33 | + |
| 34 | +This diagram shows how **`EditorPlaybackManager`** coordinates **`loadPreview`** / **`play`**, how **`PreviewTimelineCompositionBuilder`** scans tracks and aggregates sources, and how the assembler + AVFoundation produce an **`AVPlayerItem`** for the preview layer. |
| 35 | + |
| 36 | + |
| 37 | + |
| 38 | +### Domain contract |
| 39 | + |
| 40 | +- **`EditingProject`** (`Domain/Models/`): The serializable project — tracks, clips, timeline/source time ranges, export settings. Track order implies **z-order** (later tracks draw on top). |
| 41 | +- **`CompositionBuilding`** (`Domain/Protocols/CompositionBuilding.swift`): `build(from: EditingProject)` → **`CompositionBuildResult`** (`AVPlayerItem` + `AVComposition` + `AVVideoComposition`, plus optional overlay layers). |
| 42 | + |
| 43 | +### Default engine (`Engine/`) |
| 44 | + |
| 45 | +**`PreviewTimelineCompositionBuilder`** implements `CompositionBuilding`: |
| 46 | + |
| 47 | +1. Computes project duration and a fixed preview **render size** (1080×1920). |
| 48 | +2. Walks **video** and **overlay** tracks and turns each supported clip into internal preview sources (file video maps source range → timeline; still images use a tiny bundled **donor** video so AVFoundation has real samples). |
| 49 | +3. **`PreviewCompositionAssembler`** (`PreviewVideoCompositionCore.swift`) builds an **`AVMutableComposition`** and a custom **`AVMutableVideoComposition`** (Core Image–based compositing for stacking, effects, transitions). |
| 50 | +4. **Audio** clips are inserted on separate composition audio tracks; tracks are **padded** to the full project length with empty ranges where needed. |
| 51 | +5. Wraps the composition in **`AVPlayerItem`**, attaches `videoComposition` / `audioMix` when present, and returns the result. |
| 52 | + |
| 53 | +Other asset types (e.g. some identifiers) may be skipped until implemented — the builder only includes what it can turn into composition segments. |
| 54 | + |
| 55 | +### UI wiring (`EditorPlaybackManager` + editor screen) |
| 56 | + |
| 57 | +- **`EditorViewModel.projectSnapshot()`** produces an **`EditingProject`** that reflects the current timeline (including edits). Playback always uses this snapshot, not a stale copy. |
| 58 | +- **`EditorPlaybackManager`** holds a **`CompositionBuilding`** instance (default: `PreviewTimelineCompositionBuilder`), an **`AVPlayer`**, and an **`AVPlayerLayer`** placed inside **`EditorRenderView`**’s canvas. |
| 59 | +- **First appearance:** `EditorViewController` calls **`loadPreview`**: build composition, attach/replace the player item, **pause at time zero** (thumbnail-style first frame). |
| 60 | +- **Toolbar play:** **`play`** runs **`build` again** with the latest snapshot, then **`player.play()`**. Pause only pauses — no rebuild. |
| 61 | + |
| 62 | +Playhead updates come from a periodic time observer on the player; reaching the end triggers pause and resets the toolbar play state. |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +## Roadmap |
| 67 | + |
| 68 | +- Media import (Photos / Videos / Audio) ✅ |
| 69 | +- Timeline + trim media items ✅ |
| 70 | +- Create Composition builder (accepts image & video & audio and converts them into composition & playerItem) ✅ |
| 71 | +- Composition builder optimizations (working on it) |
| 72 | +- EditorTimelineView optimizations for play, fast scrub debounce etc. |
| 73 | +- Add transition between media items ✅ |
| 74 | +- Add overlay media items support like sticker and text (working on it) |
| 75 | +- Add applying effects to media items (like glitch etc) |
| 76 | +- Add applying core image & custom filter to media items |
| 77 | +- HDR support |
| 78 | +- Higher render size support |
| 79 | +- Export pipeline (presets/bitrate) ✅ |
| 80 | +- Add export file type (.mp4, .mov) ✅ |
| 81 | + |
| 82 | +> **Production notice:** This project is currently a “playground” and should not be considered production-ready. |
0 commit comments