如何追加分块传输的视频Blob数据并生成完整播放URL?
分块视频数据合并为Blob后播放异常的解决方案
问题根源
- 异步请求顺序混乱:你在for循环里并行发起了5个分块请求,每个请求的响应时间不确定,导致
myBlobBuilder.parts中的块顺序可能和视频实际分块顺序不一致。MP4是结构化容器格式,块顺序错误会直接导致视频只能播放开头部分。 - 分块单位可能不匹配:代码中用
sizeInKB /5计算每块大小,但如果API的offset和length参数要求的是字节而非KB,这种计算会导致请求的块范围错误,最终合并的Blob内容不完整或顺序错乱。
修复代码示例
var MyBlobBuilder = function() { this.parts = []; }; MyBlobBuilder.prototype.append = function(part) { this.parts.push(part); this.blob = undefined; }; MyBlobBuilder.prototype.getBlob = function() { if (!this.blob) { this.blob = new Blob(this.parts, { type: 'video/mp4' }); } return this.blob; }; let myBlobBuilder = new MyBlobBuilder(); async function handleResourceClick(resource) { try { const x = await dispatch(fetchFileType(resource)); // 若API参数为字节单位,需将KB转换为字节(乘以1024) const totalSizeBytes = x.payload.data.sizeInKB * 1024; const chunkSizeBytes = Math.ceil(totalSizeBytes / 5); let startByte = 0; // 串行发起请求,确保块顺序严格匹配视频分块顺序 for (let i = 0; i < 5 && startByte < totalSizeBytes; i++) { // 最后一块取剩余大小,避免超出总尺寸 const currentChunkSize = Math.min(chunkSizeBytes, totalSizeBytes - startByte); const res = await dispatch(getVideoUrl({ pdfUrl: resource, offset: startByte, length: currentChunkSize })); if (isApiSuccess(res)) { myBlobBuilder.append(res.payload?.data); } startByte += currentChunkSize; } // 生成完整视频的Blob URL const finalBlob = myBlobBuilder.getBlob(); const videoUrl = URL.createObjectURL(finalBlob); // 将videoUrl赋值给video元素的src即可播放 } catch (error) { console.error('分块请求失败:', error); } }
额外注意事项
- 确认API参数单位:核实
getVideoUrl接口的offset和length是按KB还是字节接收,若为KB则去掉代码中*1024的转换逻辑。 - 检查响应数据类型:确保
res.payload.data是ArrayBuffer或Blob类型,若返回的是base64字符串,需先转换为ArrayBuffer再追加到BlobBuilder中。 - 及时释放内存:使用完生成的
videoUrl后,调用URL.revokeObjectURL(videoUrl)释放浏览器内存。
内容的提问来源于stack exchange,提问作者Anurag
相关产品推荐
相关产品推荐

