20260429_232813-fix: video frame display pipeline — default project seed, presigned URLs, Canvas/FrameTimeline real frames, upload-parse flow
This commit is contained in:
66
工程分析/实现方案-20260429_232813.md
Normal file
66
工程分析/实现方案-20260429_232813.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# 实现方案 — 视频帧显示链路修复
|
||||
|
||||
## 后端
|
||||
|
||||
### 1. `backend/schemas.py` — ProjectOut 增加 frame_count
|
||||
```python
|
||||
class ProjectOut(ProjectBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
frame_count: int = 0
|
||||
```
|
||||
|
||||
### 2. `backend/routers/projects.py` — 三处修改
|
||||
- `list_projects`: 为每个项目计算 `frame_count = len(p.frames)`(利用 ORM relationship)
|
||||
- `list_frames`: 返回前将每个 `frame.image_url` 替换为 `get_presigned_url(frame.image_url, expires=3600)`
|
||||
- `get_project`: 同样添加 `frame_count`
|
||||
|
||||
### 3. `backend/main.py` — lifespan 默认视频种子
|
||||
启动时异步后台任务:
|
||||
- 若数据库无项目且 `Data_MyVideo_1.mp4` 存在
|
||||
- 创建 Project → 上传 MinIO → 调用 FFmpeg 解析帧 → 上传帧到 MinIO → 注册 Frame 记录 → 更新 status="ready"
|
||||
- 使用 `asyncio.to_thread()` 避免阻塞事件循环
|
||||
|
||||
### 4. `backend/routers/media.py` — upload 自动创建项目
|
||||
当 `project_id` 为空时:
|
||||
- 以文件名创建 Project
|
||||
- 将上传文件关联到该 project
|
||||
- 返回中增加 `project_id`
|
||||
|
||||
## 前端
|
||||
|
||||
### 5. `src/lib/api.ts` — 新增两个 API
|
||||
```ts
|
||||
export async function getProjectFrames(projectId: string): Promise<Array<{ id: number; project_id: number; frame_index: number; image_url: string; width: number | null; height: number | null }>>
|
||||
export async function parseMedia(projectId: string): Promise<{ project_id: number; frames_extracted: number; status: string; message: string }>
|
||||
```
|
||||
|
||||
### 6. `src/components/VideoWorkspace.tsx` — 帧加载中枢
|
||||
- 读取 `currentProject` 和 `frames`
|
||||
- `useEffect` 监听 `currentProject.id`:
|
||||
- 调用 `getProjectFrames`
|
||||
- 映射后端字段到前端 `Frame[]` 结构写入 store
|
||||
- 若帧数为 0 且项目有 video_path,自动调用 `parseMedia` 触发解析,解析完成后重新获取
|
||||
- 将当前帧 URL 通过 prop 传给 `CanvasArea`
|
||||
- 将帧列表和索引控制传给 `FrameTimeline`
|
||||
- 标题显示 `currentProject?.name`
|
||||
|
||||
### 7. `src/components/CanvasArea.tsx` — 真实帧渲染
|
||||
- 新增 `frameUrl` prop
|
||||
- `const [image] = useImage(frameUrl || '')`
|
||||
- `runInference` 使用 `frameUrl` 替代硬编码 URL
|
||||
|
||||
### 8. `src/components/FrameTimeline.tsx` — 真实帧导航
|
||||
- 从 store 读取 `frames` 和 `currentFrameIndex`
|
||||
- `totalFrames = frames.length`
|
||||
- 每个帧方块显示为 `<img>` 缩略图
|
||||
- 点击调用 `setCurrentFrame(index)`
|
||||
- 进度条范围 1..frames.length
|
||||
|
||||
### 9. `src/components/ProjectLibrary.tsx` — 完整上传链路
|
||||
上传流程改为:
|
||||
1. `createProject({ name: file.name })`
|
||||
2. `uploadMedia(file, projectId)`
|
||||
3. `parseMedia(projectId)`
|
||||
4. `getProjects()` 刷新列表
|
||||
Reference in New Issue
Block a user