上传优化:视频消息实现边压缩边上传,实现高速传输

4,241 阅读3分钟

社交软件中少不了视频消息的发送,视频消息的发送速度将直接影响到用户收发消息的体验。

我们先来看下优化前视频消息压缩、上传以及发送流程:

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
压缩算法H264High40H264 兼容性较好
分辨率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: 上传成功

注意事项:

  1. 每个请求都需要 token 鉴权

  2. 请求会偶现 502,重新请求即可

  3. 合并流的请求需要按照 partNumber 的顺序传 ETag

  4. 控制分片上传时的个数

优化结果

上传时间较之前减少 60%

优化 3:视频边压缩边上传优化

进一步优化上传时间,在视频压缩到 1/3 的时候,在满足分片的情况下,将该片返回上层进行分片上传,实现边压缩边上传,变向的减少一些上传时间。

最终优化结果

视频消息发送时,压缩+上传时间较之前减少 67%。