Skip to content

Commit 8df0cd3

Browse files
committed
Initial Commit: Cleaned and Restructured
0 parents  commit 8df0cd3

12 files changed

Lines changed: 1468 additions & 0 deletions

File tree

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.github/workflows/swift.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: iOS Build
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
build:
15+
name: Build (Simulator)
16+
runs-on: macos-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v5
20+
21+
- name: Select Xcode
22+
uses: maxim-lobanov/setup-xcode@v1
23+
with:
24+
xcode-version: latest-stable
25+
26+
- name: Resolve Xcode project and verify scheme
27+
run: |
28+
set -euo pipefail
29+
ROOT="$GITHUB_WORKSPACE"
30+
PROJ="$ROOT/VideoEditor.xcodeproj"
31+
if [[ ! -f "$PROJ/project.pbxproj" ]]; then
32+
PROJ=$(find "$ROOT" -name "VideoEditor.xcodeproj" -type d 2>/dev/null | head -1 || true)
33+
fi
34+
if [[ -z "${PROJ:-}" ]] || [[ ! -f "$PROJ/project.pbxproj" ]]; then
35+
echo "::error::VideoEditor.xcodeproj not found under $ROOT"
36+
echo "Discovered .xcodeproj paths (max depth 8):"
37+
find "$ROOT" -maxdepth 8 -name "*.xcodeproj" -type d 2>/dev/null || true
38+
echo "Repository root listing:"
39+
ls -la "$ROOT"
40+
exit 1
41+
fi
42+
echo "Using Xcode project: $PROJ"
43+
echo "XCODEPROJ=$PROJ" >> "$GITHUB_ENV"
44+
SCHEME_FILE="$PROJ/xcshareddata/xcschemes/VideoEditor.xcscheme"
45+
if [[ ! -f "$SCHEME_FILE" ]]; then
46+
echo "::error::Shared scheme missing: $SCHEME_FILE"
47+
echo "In Xcode: Product → Scheme → Manage Schemes → enable Shared for VideoEditor, then commit xcshareddata/xcschemes/."
48+
exit 1
49+
fi
50+
xcodebuild -list -project "$PROJ"
51+
52+
- name: Build
53+
run: |
54+
set -euo pipefail
55+
DERIVED_DATA="$RUNNER_TEMP/DerivedData-VideoEditor"
56+
mkdir -p "$DERIVED_DATA"
57+
xcodebuild \
58+
-project "$XCODEPROJ" \
59+
-scheme VideoEditor \
60+
-configuration Debug \
61+
-destination 'generic/platform=iOS Simulator' \
62+
-derivedDataPath "$DERIVED_DATA" \
63+
build

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
.cursor/

README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
![Engine: composition builder pipeline (playback → builder → assembler → AVFoundation)](VideoEditorCompositionBuilderPiplinePicture.png)
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.

VideoEditor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 71e7e415fcf908add4d3ea5bf83ca7c11bb3bda9

0 commit comments

Comments
 (0)