# 儿童流媒体视频播放器 — 架构设计 > 版本:v0.6(2026-06-13)。v0.2:入库**默认不转码**;播放从 HLS 简化为 MP4 渐进式。v0.3:新增后台网页直传。v0.4:上传 CLI `cpv` 落地为一等公民(供 AI 调用,已实现于 `cli/`),播放列表单一事实源改为 R2 中的 `manifest.json`。v0.5:孩子端定为**原生 SwiftUI 多平台 App(iPhone / iPad / Mac)**,移除 PWA 方案。v0.6:分发改为 **SideStore 免费侧载**(不交 $99/年)。 > 目标:家长定期上传视频,孩子在一个**封闭内容花园**里观看——没有推荐流、没有外部内容入口、没有广告,孩子只能看到家长放进去的东西。 --- ## 1. 设计原则 1. **封闭花园**:孩子端不存在任何"打开外部世界"的入口(无搜索外网、无 WebView 浏览、无推荐算法)。内容只来自家长上传。 2. **格式收敛在入库侧,而不是播放侧**:三个参考项目(QPlayer 等)之所以要堆 ijkplayer/FFmpeg 多内核兜底,是因为它们要接受任意格式。我们反过来——入库时统一收敛为 H.264/AAC 的 MP4。互联网来源的视频绝大多数本来就是这个格式,所以"收敛"通常只是秒级的重封装而**不是转码**(见 §4.2)。播放端全是 Apple 平台(iPhone/iPad/Mac),统一用系统 **AVPlayer**,不需要任何第三方解码内核。 3. **成本随字节走,不随时长走**:用对象存储(按 GB 计费)+ 免费出口流量,避开按"视频分钟数"计费的托管方案(见 §6 成本分析)。 4. **家庭量级,不过度设计**:观众 1–3 人,不需要鉴权服务集群、不需要多区域、不需要 ABR 多码率(先单码率,需要再加)。 --- ## 2. 来自三个参考项目的取舍 | 项目 | 定位 | 借鉴 | 忽略 | |---|---|---|---| | [QPlayer](https://github.com/itenfay/QPlayer) (iOS) | 完整的本地视频播放 App,WiFi 上传 + 多内核 | ① 播放内核独立成"管理层",业务层不绑定具体播放器;② MVP 分层工程结构;③ WiFi 局域网上传的轻量思路(我们的 MVP 阶段可用类似思路做局域网直传) | ① Web 在线视频解析功能——这是**儿童安全红线**,孩子端绝不能有;② KSYMediaPlayer 商业 SDK;③ ijkplayer 软解兜底(我们格式统一后不需要) | | [Collected-VideoViewPlayer](https://github.com/sendtion/Collected-VideoViewPlayer) | 播放器项目链接清单(无代码,已停更) | 其中 ArtPlayer 体现的"播放内核可插拔抽象"思路 | 仓库本身只是导航页 | | [EasyPlayer](https://github.com/tsingsee/EasyPlayer) | 安防监控低延迟 RTSP/RTMP SDK(主仓库 2017 年后停更) | 流/文件加密保护私有内容的思路 | 整个 RTSP/RTMP 低延迟直播栈——我们是点播(VOD),协议栈完全用不上 | 三个项目都缺、需要我们自建的:**家长控制(PIN、时长限制)**、**儿童友好 UI**、**云端内容库**。 --- ## 3. 总体架构 ```mermaid flowchart LR subgraph 家长侧 A[互联网下载的视频
yt-dlp / 浏览器下载] --> C[上传 CLI cpv
供 AI / 终端调用] A --> P[家长管理台网页
浏览器内探测编码 + 生成封面] C -->|S3 API 直传 + 更新 manifest.json| R2 P -->|预签名 multipart 分片直传| R2 P -->|登记元数据 / 配置规则| W end subgraph Cloudflare R2[(R2 对象存储
MP4 + 封面图)] W[Workers API] --> D1[(D1 数据库
视频元数据/播放进度/规则)] W -->|R2 binding 读取| R2 PG[Pages
托管管理台 + 孩子端 PWA] end subgraph 孩子侧 K[SwiftUI App
iPhone / iPad / Mac] -->|带设备令牌请求| W W -->|MP4 字节流(Range)| K end ``` **一个 Cloudflare 账号跑通云端全部**:Pages(家长管理台,免费)+ Workers(API + 媒体网关,免费额度内)+ D1(进度/规则,免费额度内)+ R2(视频存储,唯一的实际云端开销)。孩子端是原生 App,不依赖 Pages。 --- ## 4. 分层设计 ### 4.1 存储层(R2) Bucket 保持**私有**,目录布局: ``` manifest.json # 播放列表(视频库的单一事实源):CLI/管理台写,播放器读 videos/{video_id}/video.mp4 # H.264/AAC + faststart,单文件渐进式播放 videos/{video_id}/poster.jpg # 封面图 ``` - 互联网来源的 720p 视频通常 1–2.5 Mbps,1 小时 ≈ 0.5–1.1 GB,直接入库即可。 - **选 MP4 渐进式而非 HLS**:家庭场景没有弱网 ABR 需求,单文件配合 HTTP Range 请求即可流畅起播和拖动进度,还省去切片产生的海量小请求、离线下载也不用拼装。未来真需要 HLS 时,用 `ffmpeg -c copy` 几秒就能从 MP4 重新打包,不锁死。 ### 4.2 入库流水线 —— 后台网页上传,默认不转码 **主路径完全在管理台网页里完成**,家长不需要在电脑上装任何工具: 1. 打开管理台(家长鉴权后),把下载好的视频拖进上传框; 2. 页面在浏览器内解析文件头(mp4box.js)探测编码:H.264/AAC 的 MP4(互联网视频的绝大多数)直接进入下一步;不兼容的文件当场提示,走下方转码兜底; 3. 浏览器经 **R2 预签名 multipart URL 分片直传**。视频字节**不能**经 Worker 转发——Workers 请求体上限 100 MB,直传 R2 是必须的设计,顺带不占任何 Worker 配额; 4. 封面图和时长在浏览器内生成(`