iPhone端Safari/Chrome无法播放跨端上传的HTML5视频,报NotSupportedError
iOS端视频播放NotSupportedError问题排查与修复
问题描述
开发了两段脚本:一段录制视频并上传至Bubble服务器,另一段通过上传后的URL播放视频。该功能在多数平台浏览器正常,但iPhone的Safari/Chrome浏览器存在异常:视频可成功上传,但播放时抛出NotSupportedError。仅iPhone浏览器上传的视频能在iPhone端正常播放,Mac/Windows上传的视频无法在iPhone端播放,问题出在上传或播放的细节处理上。
原脚本代码
脚本1:录制并上传视频
let mediaRecorder; let cameraView; let recordedChunks = []; // 存储流数据的数组 instance.data.streamWebcam = await getCamera(); mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = function (e) { if (e.data.size > 0) { recordedChunks.push(e.data); } }; mediaRecorder.onstop = function () { const blob = new Blob(recordedChunks, { type: 'video/mp4' }); var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = function () { var filename = 'video_' + (new Date()).getTime() + '.mp4'; var base64data = reader.result; var uploadData = base64data.substr(base64data.indexOf(',') + 1); context.uploadContent(filename, uploadData, function (err, url) { // 上传至Bubble数据库 URL.revokeObjectURL(blob); }); } }; cameraView = document.createElement('video'); // 创建视频元素 cameraView.srcObject = instance.data.streamWebcam; cameraView.style.width = '100%'; cameraView.style.height = '100%'; cameraView.style.overflow = 'hidden'; cameraView.style.objectFit = 'cover'; cameraView.style.display = 'block'; cameraView.muted = true; cameraView.autoplay = true; cameraView.playsInline = true; cameraView.onloadedmetadata = function (e) { cameraView.play(); // 加载后播放视频 }; instance.canvas.append(cameraView); // 添加元素到画布 mediaRecorder.start(200);
脚本2:通过URL播放视频
let playerVideo = document.createElement('video'); playerVideo.type = 'video/mp4' playerVideo.style.overflow = 'hidden'; playerVideo.style.objectFit = 'cover'; playerVideo.style.display = 'block'; playerVideo.src = playerVideoUrl + "#t=0.001"; playerVideo.controls = field_showControls; playerVideo.autoplay = autoplayValue; playerVideo.muted = true; playerVideo.playsInline = true; playerVideo.style.width = '100%'; playerVideo.style.height = '100%'; instance.canvas.append(playerVideo); playerVideo.play();
问题根源
iOS的Safari/Chrome对视频编码有严格限制,仅支持H.264(Baseline/Main/High profile)+ AAC音频的MP4格式。而Mac/Windows平台的MediaRecorder默认可能生成VP8/VP9等非兼容编码的MP4容器(虽后缀为mp4,但编码不被iOS识别),导致播放时抛出格式不支持错误。
修复方案
1. 上传阶段:强制指定iOS兼容的编码格式
修改MediaRecorder初始化参数,明确指定兼容的MIME类型,确保生成的视频编码符合iOS要求:
// 替换原mediaRecorder初始化代码 const options = { mimeType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' // H.264 Baseline + AAC }; // 检查浏览器是否支持该编码,不支持则降级为默认MP4 mediaRecorder = MediaRecorder.isTypeSupported(options.mimeType) ? new MediaRecorder(stream, options) : new MediaRecorder(stream, { mimeType: 'video/mp4' });
2. 上传阶段:优化Blob上传方式(可选)
原脚本将Blob转Base64上传,可能增加体积和潜在编码问题。若Bubble的uploadContent支持直接上传Blob,建议简化流程:
// 替换原mediaRecorder.onstop代码 mediaRecorder.onstop = function () { const blob = new Blob(recordedChunks, { type: 'video/mp4' }); const filename = 'video_' + (new Date()).getTime() + '.mp4'; // 直接上传Blob(需确认Bubble API支持) context.uploadContent(filename, blob, function (err, url) { URL.revokeObjectURL(blob); }); };
3. 播放阶段:优化iOS播放逻辑
- 移除URL末尾的
#t=0.001,避免iOS片段播放兼容问题 - 监听
canplay事件再触发播放,避免过早调用导致错误 - 添加错误监听便于排查
// 替换原脚本2代码 let playerVideo = document.createElement('video'); playerVideo.type = 'video/mp4'; playerVideo.style.overflow = 'hidden'; playerVideo.style.objectFit = 'cover'; playerVideo.style.display = 'block'; playerVideo.src = playerVideoUrl; // 移除#t=0.001 playerVideo.controls = field_showControls; playerVideo.autoplay = autoplayValue; playerVideo.muted = true; playerVideo.playsInline = true; playerVideo.style.width = '100%'; playerVideo.style.height = '100%'; // 添加错误监听 playerVideo.onerror = (e) => console.error('视频播放错误:', e.error); // 等待视频可播放后再触发自动播放 playerVideo.addEventListener('canplay', () => { if (autoplayValue) { playerVideo.play().catch(err => console.error('自动播放失败:', err)); } }); instance.canvas.append(playerVideo);
4. 验证视频编码(可选)
用ffmpeg工具检查上传后的视频编码,确认是否为iOS兼容格式:
ffmpeg -i 上传后的视频URL或本地文件路径
输出中需包含Video: h264和Audio: aac,否则说明编码指定未生效,需调整MediaRecorder参数。
内容的提问来源于stack exchange,提问作者user8209191
相关产品推荐
相关产品推荐

