社交软件中少不了视频消息的发送,视频消息的发送速度将直接影响到用户收发消息的体验。
我们先来看下优化前视频消息压缩、上传以及发送流程:
sequenceDiagram
AppA->>AppA: 发送端进行视频压缩
AppA->>File Server: 上传压缩后的视频
File Server-->>AppA: 返回视频地址
AppA->>IM Server: 发送端发送视频消息
优化 1:视频压缩优化
优化前
先看一下优化前的视频压缩,通过系统 AVAssetExportSession 压缩,使用内置的分辨率进行压缩;这么压缩出来有一些问题,要么是视频文件有些大,要么是视频有些模糊。
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPreset960x540];
session.outputFileType = AVFileTypeMPEG4;
session.outputURL = [NSURL fileURLWithPath:localPath];
[session exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = session.status;
if (status == AVAssetExportSessionStatusCompleted) {
// 视频压缩完成
// 将压缩后的视频路径记录在 message 中
} else {
// 视频压缩失败
// 处理失败情况
}
}];
苹果内置参数: 苹果视频压缩内置参数 Export Presets
优化后
修改为自定义压缩参数,通过 AVAssetWriter 和 AVAssetReader 按照预设的视频参数和音频参数压缩小视频
| 视频参数 | 参考值 | 备注 |
|---|---|---|
| 视频类型 | mpeg4 | |
| 视频路径 | localPath | |
| 压缩算法 | H264High40 | H264 兼容性较好 |
| 分辨率 | 384*848 | 参考的 WhatsApp 视频分辨率 |
| 比特率 | 计算 | videoSize.height * videoSize.width * 帧率(30) * 常数(每个像素点内的像素数据) |
| 关键帧 | 30 | 建议大于 25,防止看着卡顿 |
| 音频参数 | 参数值 |
|---|---|
| 音频格式 | aac |
| 声道 | 单声道 |
| 采样率 | 44100 |
| 比特率 | 128000 |
LSAVAssetExportSession *session = [[LSAVAssetExportSession alloc] initWithAsset:asset];
session.delegate = self;
session.outputFileType = AVFileTypeMPEG4;
session.outputURL = [NSURL fileURLWithPath:localPath];
NSString *videoProfileLevel = AVVideoProfileLevelH264HighAutoLevel;
CGSize videoSize = [self getSuitableVideoSize:asset];
// bitrate: videoSize.height * videoSize.width * 帧率(30) * 常数(每个像素点内的像素数据)
NSInteger bitrate = videoSize.height * videoSize.width * 30 * 0.15;
// 视频参数设置
session.videoSettings = @{
AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(videoSize.width),
AVVideoHeightKey : @(videoSize.height),
AVVideoCompressionPropertiesKey : @{
///选择视频颜色编码格式(默认格式会支持HDR, 导致视频在 mac 版本泛白)
///默认为: AVVideoYCbCrMatrix_*ITU_R_2020, 为支持 HDR 的格式, 应当指定为 ITU*_R_*709*_2 通用配置
AVVideoColorPrimariesKey : AVVideoColorPrimaries_ITU_R_709_2,
AVVideoAverageBitRateKey : @(bitrate), // 比特率
AVVideoProfileLevelKey : videoProfileLevel, // 压缩算法
AVVideoMaxKeyFrameIntervalKey : @(30), // 关键帧间隔
},
};
// 音频参数设置
session.audioSettings = @{
AVFormatIDKey : @(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey : @1,
AVSampleRateKey : @44100,
AVEncoderBitRateKey : @128000,
};
[session exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = session.status;
if (status == AVAssetExportSessionStatusCompleted) {
// 视频压缩完成
// 将压缩后的视频路径记录在 message 中
} else {
// 视频压缩失败
// 处理失败情况
}
}];
优化结果
小视频消息清晰度优化,在分辨率和 WhatsApp 相同的情况下,比其小很多。
此处直接使用官方数据
视频源文件大小在 120M 左右,经过压缩后,大小可降低至 44M,保障清晰度的情况下,有效压缩率为 37% 左右。
优化 2:视频上传优化
优化前
刚开始是整个视频直接上传,遇到网络问题或者其他问题会导致上传流程失败,重新上传需要从 0 开始,用户体验较差。
优化后
通过将压缩后的视频分片,并发上传,失败重试,提高上传成功率,减少上传等待时间,极大的降低网络影响。
sequenceDiagram
AppA->>AppA: 发送端进行视频压缩
AppA->>AppA: 视频分片
AppA->>File Server: 初始化视频分片上传请求
File Server-->>AppA: 返回 uploadId
AppA->>File Server: 分片并发上传(最多 4 片),携带 uploadId 和 partNumber
File Server-->>AppA: 成功/失败,成功返回 ETag,失败进行重试机制
AppA->>File Server: 分片上传结束,告诉服务进行合并
File Server-->>AppA: 上传成功
注意事项:
每个请求都需要 token 鉴权
请求会偶现 502,重新请求即可
合并流的请求需要按照 partNumber 的顺序传 ETag
控制分片上传时的个数
优化结果
上传时间较之前减少 60%
优化 3:视频边压缩边上传优化
进一步优化上传时间,在视频压缩到 1/3 的时候,在满足分片的情况下,将该片返回上层进行分片上传,实现边压缩边上传,变向的减少一些上传时间。
最终优化结果
视频消息发送时,压缩+上传时间较之前减少 67%。