Files
to-live-photo/docs/TECHSPEC_LivePhoto_App_V0.2_2025-12-13.md
empty 299415a530 feat: 初始化 Live Photo 项目结构
- 添加 PRD、技术规范、交互规范文档 (V0.2)
- 创建 Swift Package 和 Xcode 项目
- 实现 LivePhotoCore 基础模块
- 添加 HEIC MakerNote 元数据写入功能
- 创建项目结构文档和任务清单
- 添加 .gitignore 忽略规则
2025-12-14 16:21:20 +08:00

168 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术规格书Live Photo 制作与动态壁纸引导 AppV0.2-Tech
- 适用平台iPhone / iPadiOS / iPadOS
- 日期2025-12-13Asia/Manila
- 用途:用于 AI 编码 / 架构落地 / 研发验收
## 1. 范围与目标
本技术规格书覆盖媒体导入、编辑、Live Photo 合成与写入、校验、壁纸引导、缓存与日志、埋点。
- **目标**:在不使用私有 API 的前提下,生成系统相册可识别的 Live Photo 资产,并通过引导帮助用户设置锁屏动态壁纸。
- **非目标**:不直接替用户设置系统壁纸;不做云端上传/存储(默认本地)。
## 2. 总体架构
### 2.1 模块分层
| 层级 | 模块 | 职责 | 关键技术 |
|---|---|---|---|
| UI | Home/Editor/Processing/Result/Guide | 页面展示、交互、状态驱动 | SwiftUI推荐/UIKit |
| Domain | Workflows | 导入-编辑-生成-保存-引导的业务编排 | async/await, Combine(可选) |
| Service | MediaImport / Builder / AlbumWriter / Validation | 导入、合成、写相册、校验 | PhotosUI, AVFoundation, Photos, ImageIO |
| Infra | CacheManager / Logger / Analytics | 缓存、日志、埋点、错误封装 | FileManager, OSLog, 自研/第三方 |
### 2.2 目录结构建议Xcode
- App/入口、DI、AppState
- Features/Home, Features/Editor, Features/Processing, Features/Result, Features/Guide
- Domain/ModelsWorkItem、ExportParams、Capability
- Domain/UseCasesImportVideo、BuildLivePhoto、SaveToAlbum、Validate、GenerateGuideSteps
- Services/MediaImport, Services/LivePhotoBuilder, Services/AlbumWriter, Services/Validation
- Infra/Cache, Infra/Logging, Infra/Analytics, Infra/Errors
- Resources/引导图、FAQ 文案、模板配置 JSON
## 3. 核心数据模型
### 3.1 WorkItem作品
| 字段 | 类型 | 说明 |
|---|---|---|
| id | UUID | 作品唯一标识 |
| createdAt | Date | 创建时间 |
| sourceVideo | SourceRef | 来源引用PHAsset localIdentifier 或 fileURL |
| coverImage | SourceRef? | 可选封面图引用 |
| exportParams | ExportParams | 比例/裁剪/关键帧等参数 |
| status | enum | idle/editing/processing/success/failed |
| resultAssetId | String? | 写入相册后的 asset.localIdentifier |
| cacheDir | URL | 中间文件目录 |
| error | AppError? | 失败信息(含可行动建议) |
### 3.2 ExportParams导出参数
| 字段 | 类型 | 说明/规则 |
|---|---|---|
| aspectRatio | Preset/CGFloat | 模板iPhoneLock、Full、4:3… |
| cropTransform | scale + offset | 编辑页输出的裁剪参数 |
| trimStart | Double | 秒默认0 |
| trimEnd | Double | 秒默认3限制1.5~5 |
| keyFrameTime | Double | 秒在trim区间内 |
| audioPolicy | enum | keep/remove默认keep |
| codecPolicy | enum | passthrough / fallbackH264 |
| hdrPolicy | enum | keep / toneMapToSDR建议 |
| maxDimension | Int | 上限,例如 1920 或自适应 |
## 4. 状态机与工作流
### 4.1 作品状态机(建议)
- Idle未开始
- → Importing导入中→ Editing编辑中
- → Processing生成中Normalize → BuildPhoto → BuildVideo → Pairing → Validate
- → Success成功可保存/已保存)
- → Failed失败含可重试点与建议
处理阶段建议暴露为枚举(用于进度与日志):
- normalize归一化裁剪/转码策略确定)
- extractKeyFrame取关键帧/封面图)
- writePhotoMetadata写图片侧元数据
- writeVideoMetadata重封装并写视频侧元数据
- saveToAlbum写入相册
- validate校验 Live Photo 是否可识别)
### 4.2 并发与取消
- 生成任务使用 TaskSwift Concurrency实现可被用户取消取消时清理未写入相册的中间文件。
- 对 AVAssetReader/Writer 的写入任务采用串行队列/actor 封装,避免资源竞争。
- 避免主线程阻塞:任何转码/重封装/写文件都在后台队列或 Task 中执行。
## 5. Live Photo 合成实现规范
### 5.1 输入约束与预处理Normalize
- 时长:将 trim 区间限制在 1.5~5s默认 3s
- 分辨率:按 maxDimension 缩放;优先保证主体清晰而不是极限画质。
- 帧率:高帧率(>30fps可降至 30fps以提升兼容性与体积。
- HDR若检测到 HDR/Dolby Vision优先提示并建议转 SDRtone mapping避免部分系统/场景识别异常。
### 5.2 绑定标识Identifier
- 每次生成一个 assetIdentifierUUID string
- 图片与视频必须共享同一 identifier否则系统不会将其识别为 Live Photo 对。
### 5.3 图片侧Photo输出规范
- 优先输出 HEIC更现代且在较新系统上更稳定必要时支持 JPEG 作为降级。
- 写入 Apple MakerNote/相关字段以携带 identifier实现时以可验证的字段集合为准
- 封面图来源优先级:用户选封面照片 > 从视频 keyFrameTime 抽帧。
### 5.4 视频侧Paired Video输出规范
- 容器MOV。
- 写入 QuickTime metadatacontent identifier与照片一致
- 写入 timed metadata trackstill-image-time标记关键照片时刻
- 尽量 re-mux不重编码提升速度若写入失败或素材不兼容再降级到转码流程。
### 5.5 写入相册规范
- 使用 PHAssetCreationRequest 同时 addResource.photo 与 .pairedVideo。
- 在 performChanges 回调中记录成功/失败;成功后写入 resultAssetId失败需返回可行动错误。
### 5.6 校验Validation
- 策略 A保存后用 resultAssetId 取回 PHAsset尝试请求 Live Photo或检查其资源类型/子资源)。
- 策略 B若无法直接取 Live Photo 对象,则至少验证:相册中显示 Live 标识(人工/自动化截图对比可作为 QA 手段)。
- 校验失败要区分:合成失败 vs 写相册失败 vs 系统未识别。
## 6. 错误码与可行动建议Error Taxonomy
| 错误码 | 阶段 | 用户可见文案(标题) | 常见原因 | 建议动作App 提示) |
|---|---|---|---|---|
| LPB-001 | Import | 无法读取视频 | 权限不足/资源损坏 | 检查相册权限;换一个视频 |
| LPB-101 | Normalize | 素材参数不兼容 | HDR/超高分辨率/奇怪编码 | 开启“兼容模式”;降低分辨率/转 SDR |
| LPB-201 | Photo | 封面生成失败 | 抽帧失败/内存不足 | 缩短时长;降低分辨率;重试 |
| LPB-301 | Video | 视频处理失败 | 重封装/转码失败 | 切换到 H.264 兼容导出;关闭音频 |
| LPB-401 | Album | 保存到相册失败 | 无写入权限/相册忙 | 允许“添加到相册”;稍后重试 |
| LPB-501 | Validate | 系统未识别为实况 | 元数据不完整/系统限制 | 重新生成;尝试更短视频;升级系统(如需壁纸动效) |
| LPB-901 | Unknown | 发生未知错误 | 不可预期异常 | 反馈日志;重启 App重试 |
## 7. 缓存、日志与诊断
### 7.1 缓存目录结构
- `Caches/LivePhotoBuilder/{workId}/source.mov`(可选)
- `Caches/LivePhotoBuilder/{workId}/normalized.mov`(归一化输出)
- `Caches/LivePhotoBuilder/{workId}/photo.heic`(封面图)
- `Caches/LivePhotoBuilder/{workId}/paired.mov`(写入元数据后的成品视频)
- `Caches/LivePhotoBuilder/{workId}/builder.log`(阶段日志,供反馈)
### 7.2 清理策略
- 成功:保留 photo/paired 的短期缓存(例如 24h以支持“再次保存/分享”;随后自动清理。
- 失败:保留日志与关键中间文件(例如 24h方便用户一键反馈随后清理。
- 用户手动“清理缓存”:立即删除所有 workId 目录,但不影响系统相册成品。
## 8. 安全与隐私
- 默认全程本地处理,不上传用户素材。
- 日志默认不包含媒体内容本身;仅记录参数与错误码;用户反馈前需二次确认。
- 权限请求延迟到使用时,并提供用途说明与拒绝后的替代路径。
## 9. AI 编码提示(可直接复制给 AI
- 按模块创建 Swift Package 或 App 内分组;对 LivePhotoBuilder 使用 `actor` 管理状态与文件路径。
- UseCase 层提供 async 函数:`importVideo()`, `buildLivePhoto()`, `saveToAlbum()`, `validate()`.
- UI 层采用单一 source of truth`WorkItemViewState`;所有副作用通过 UseCase 注入。
- 为每个阶段输出结构化日志与 `progress (0~1)` + `stage enum`