feat: frame-based positioning and mark system foundation
Core Changes: - Fix SearchView to use start_frame/end_frame directly (no time*fps conversion) - Add hard_delete support to delete_trace API - VideoPlayer: Main timeline + Mark system foundation - Proxy: Add local routes for auth, media, identity-matches, cluster-results - Add .gitignore to exclude build artifacts and dependencies Design Documents: - Multi-track Mark system design (.opencode/plans/) - Video editing positioning standards research Files Modified: - src/views/SearchView.vue: Frame positioning, ensureMinDuration (240 frames) - src/views/PeopleView.vue: batchDeleteGroups with hard_delete - src/api/index.ts: delete_trace with hard_delete body - src/components/VideoPlayer.vue: Timeline + Mark UI - src-tauri/src/proxy.rs: New local routes - AGENTS.md: Update documentation
This commit is contained in:
186
docs/core-api-fix-video-range.md
Normal file
186
docs/core-api-fix-video-range.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# Core API Fix Request: Video Range Requests Support
|
||||
|
||||
## Issue
|
||||
|
||||
Video player in Studio cannot seek (跳轉) because Core API video endpoint does not support HTTP Range requests.
|
||||
|
||||
## Current Behavior
|
||||
|
||||
```bash
|
||||
$ curl -I "http://localhost:3002/api/v1/file/{uuid}/video?start_time=0&end_time=5"
|
||||
HTTP/1.1 200 OK
|
||||
content-type: video/mp4
|
||||
content-length: 1918410
|
||||
# Missing: Accept-Ranges header
|
||||
# Missing: 206 Partial Content support
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
```bash
|
||||
$ curl -I "http://localhost:3002/api/v1/file/{uuid}/video" -H "Range: bytes=0-1000"
|
||||
HTTP/1.1 206 Partial Content
|
||||
content-type: video/mp4
|
||||
content-range: bytes 0-1000/1918410
|
||||
accept-ranges: bytes
|
||||
content-length: 1001
|
||||
```
|
||||
|
||||
## Why This Matters
|
||||
|
||||
1. **Browser seeking requires Range support** - HTML5 `<video>` element uses Range requests to seek to different timestamps
|
||||
2. **Current workaround is inefficient** - Users must download entire video or use `start_time` param (re-downloads video)
|
||||
3. **High bitrate videos suffer most** - 4K/10Mbps videos cannot be quickly navigated
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
### 1. Add `Accept-Ranges: bytes` header to video endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/file/{uuid}/video
|
||||
Response Headers:
|
||||
Accept-Ranges: bytes
|
||||
```
|
||||
|
||||
### 2. Handle Range requests with 206 Partial Content
|
||||
|
||||
```rust
|
||||
// Pseudo-code for Rust implementation
|
||||
if let Some(range_header) = request.headers().get("Range") {
|
||||
let (start, end) = parse_range(range_header)?;
|
||||
let file_chunk = read_file_range(file_path, start, end)?;
|
||||
|
||||
Response::builder()
|
||||
.status(206)
|
||||
.header("Content-Range", format!("bytes {}-{}/{}", start, end, file_size))
|
||||
.header("Accept-Ranges", "bytes")
|
||||
.header("Content-Length", end - start + 1)
|
||||
.body(file_chunk)
|
||||
} else {
|
||||
// Full file response
|
||||
Response::builder()
|
||||
.status(200)
|
||||
.header("Accept-Ranges", "bytes")
|
||||
.body(full_file)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Support multiple Range formats
|
||||
|
||||
- `Range: bytes=0-999` (first 1000 bytes)
|
||||
- `Range: bytes=1000-` (from byte 1000 to end)
|
||||
- `Range: bytes=-500` (last 500 bytes)
|
||||
|
||||
## Affected Files (Core API)
|
||||
|
||||
- `src/api/files.rs` - Video streaming endpoint
|
||||
- Possibly `src/api/video.rs` if exists
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Test 1: Initial request should include Accept-Ranges
|
||||
curl -I "http://localhost:3002/api/v1/file/{uuid}/video"
|
||||
# Expect: Accept-Ranges: bytes
|
||||
|
||||
# Test 2: Range request should return 206
|
||||
curl -I "http://localhost:3002/api/v1/file/{uuid}/video" -H "Range: bytes=0-1000"
|
||||
# Expect: HTTP/1.1 206 Partial Content
|
||||
# Expect: Content-Range: bytes 0-1000/{total}
|
||||
|
||||
# Test 3: Browser seeking should work
|
||||
# Open Studio, play video, click on timeline
|
||||
# Video should seek without re-downloading
|
||||
```
|
||||
|
||||
## Priority
|
||||
|
||||
**High** - Critical for user experience when navigating long videos
|
||||
|
||||
## Related Studio Files
|
||||
|
||||
- `src/components/VideoPlayer.vue` - Uses `<video>` element with native controls
|
||||
- `src-tauri/src/proxy.rs` - Already streams video, will pass through Range headers
|
||||
|
||||
## Notes
|
||||
|
||||
- Studio proxy already supports streaming (lines 325-367 in proxy.rs)
|
||||
- Just need Core API to handle Range requests properly
|
||||
- This is standard HTTP behavior for video streaming
|
||||
|
||||
---
|
||||
|
||||
## Additional Request: Adaptive Bitrate / Resolution Selection
|
||||
|
||||
### Problem
|
||||
|
||||
High bitrate videos (4K, 10+ Mbps) cause playback lag in browser due to software decoding limitations.
|
||||
|
||||
### Solution Options
|
||||
|
||||
#### Option A: Resolution Parameter
|
||||
|
||||
```bash
|
||||
GET /api/v1/file/{uuid}/video?start_time=0&end_time=60&resolution=720p
|
||||
GET /api/v1/file/{uuid}/video?start_time=0&end_time=60&resolution=480p
|
||||
```
|
||||
|
||||
**Implementation:**
|
||||
- Use FFmpeg to transcode on-the-fly or pre-generate proxy versions
|
||||
- Store proxy videos at lower bitrates (720p @ 2Mbps, 480p @ 1Mbps)
|
||||
|
||||
#### Option B: Quality Parameter (1-100)
|
||||
|
||||
```bash
|
||||
GET /api/v1/file/{uuid}//video?start_time=0&end_time=60&quality=50
|
||||
```
|
||||
|
||||
#### Option C: Max Bitrate Parameter
|
||||
|
||||
```bash
|
||||
GET /api/v1/file/{uuid}/video?start_time=0&end_time=60&max_bitrate=2000
|
||||
```
|
||||
|
||||
### Recommended Approach
|
||||
|
||||
**Pre-generate proxy videos during processing:**
|
||||
|
||||
```rust
|
||||
// During file processing, generate multiple versions:
|
||||
// - Original: {uuid}_original.mp4 (preserve original quality)
|
||||
// - 720p: {uuid}_720p.mp4 (2 Mbps)
|
||||
// - 480p: {uuid}_480p.mp4 (1 Mbps)
|
||||
```
|
||||
|
||||
**Storage Impact:**
|
||||
- Original 100MB video → ~105MB total (5% overhead for proxies)
|
||||
|
||||
**API Changes:**
|
||||
|
||||
```rust
|
||||
pub fn get_video_stream(
|
||||
file_uuid: String,
|
||||
start_time: f64,
|
||||
end_time: f64,
|
||||
resolution: Option<String>, // "original" | "720p" | "480p"
|
||||
) -> Result<VideoStream, Error>
|
||||
```
|
||||
|
||||
### Frontend Integration
|
||||
|
||||
Studio VideoPlayer can add quality selector:
|
||||
|
||||
```vue
|
||||
<select v-model="selectedResolution">
|
||||
<option value="original">Original (1080p)</option>
|
||||
<option value="720p">HD (720p)</option>
|
||||
<option value="480p">SD (480p)</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Eliminates lag** on high bitrate videos
|
||||
2. **Faster loading** with smaller file sizes
|
||||
3. **Bandwidth savings** for remote access
|
||||
4. **Better UX** - smooth playback on all devices
|
||||
Reference in New Issue
Block a user