18 March 2020

项目需要用户在手机网页拍摄视频并上传,再由后台人员播放审核。几十秒的视频就可能超过 100MB,上传等待、失败重试和浏览器播放兼容都需要单独处理。

先把上传单位设计清楚

我最初采用过 Base64 分段上传,再由服务端还原视频的方式。Base64 不是压缩:每 3 字节通常编码为 4 个字符,还会增加转换与内存开销。浏览器已经拿到 File 对象时,更直接的方式是用 Blob.slice() 切二进制分片,通过 multipart 或二进制请求上传。

分片需要一个稳定的上传 ID,并携带分片序号、总数、大小及校验信息。重试同一分片应能覆盖或复用已确认结果,不能重复追加。服务端确认分片完整、顺序和文件校验正确后,再将合并结果标记为可用;未完成上传应有过期清理机制。

进度条反映的是传输进度,不代表后台合并与转码完成。界面最好区分上传、处理和可播放三个状态,并在失败时允许继续上传或重新处理。

Base64 还原不等于转换视频格式

如果接口确实接收 Data URL,需要分开元信息和 Base64 数据,例如:

data:video/mp4;base64,...
data:video/quicktime;base64,...

应按逗号分隔头部与数据,确认编码标记后解码,而不是为 Android 和 iOS 各写一条固定字符串替换。MIME 类型和扩展名都不能证明内部编码;把 QuickTime 数据解码后改成 .mp4,也不会自动得到兼容的 MP4。

如果每个二进制分片分别进行了 Base64 编码,服务端应逐片解码再按顺序拼接字节,不能随意拼接包含填充字符的 Base64 文本。

播放兼容要同时看容器和编码

网页并非只支持 H.264。可播放性取决于浏览器、设备、容器、视频编码及音频编码的组合。MP4 中使用 H.264 视频和 AAC 音频是一种常见选择,但仍需在目标设备验证。

下面是使用 FFmpeg 转码的示例,要求当前构建包含 libx264:

ffmpeg -i input.mov -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart output.mp4

CRF、分辨率和预设影响清晰度、体积与处理时间,需要用真实样本评估。+faststart 将 MP4 的播放索引移到文件前部,便于渐进播放;它不会把视频变成 HLS,也不代替服务端对 Range 请求的支持。

将耗时处理移出请求线程

合并后把转码放入后台任务,记录处理状态与失败原因。调用外部进程时使用参数列表,限制并发、超时和输出大小,并消费标准输出与错误流,避免进程阻塞。上传文件由服务端生成存储名称,不直接将用户文件名拼接到命令里。

审核端读取转码后的文件,服务端正确返回类型和范围响应。最终验收要覆盖大文件、重复分片、传输中断、转码失败、无音轨和不同设备拍摄的视频,才能说明这条链路真正可用。

参考:FFmpeg 命令行、MP4 muxer 与 faststart。





blog comments powered by Disqus
Fork me on GitHub