uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频
uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频
示例代码:
// 初始化音视频流
async initMediaStream() {
try {
navigator.mediaDevices.getMedia = navigator.mediaDevices.getUserMedia || navigator.mediaDevices.webkitGetUserMedia || navigator.mediaDevices.mozGetUserMedia || navigator.mediaDevices.msGetUserMedia;
this.mediaStream = await navigator.mediaDevices.getMedia({
video: { width: 1280, height: 720, frameRate: { min: 30, ideal: 60, max: 60 } },
audio: true,
});
// const previewVideo = document.createElement('video');
// previewVideo.src = URL.createObjectURL(this.mediaStream);
// // previewVideo.play();
// this.logMessage('stream_init', '音视频流初始化成功');
// // 创建临时 video 元素并添加到页面(仅验证用)
const previewVideo = document.createElement('video');
previewVideo.srcObject = this.mediaStream;
previewVideo.autoplay = true;
previewVideo.muted = true; // 避免回声
previewVideo.style.position = 'fixed';
previewVideo.style.top = '0';
previewVideo.style.width = '200px';
previewVideo.style.height = '200px';
previewVideo.style.border = '2px solid yellow';
document.body.appendChild(previewVideo);
return true;
} catch (e) {
this.onError({ msg: `音视频流获取失败:${e.message}` });
return false;
}
}
// 开始录像
async startRecording() {
if (this.isRecording) return;
const streamReady = await this.initMediaStream();
if (!streamReady) return;
try {
const options = {
mimeType: 'video/webm; codecs=vp8,opus',
audioBitsPerSecond: 128000,
videoBitsPerSecond: 2500000
};
const support = typeof MediaRecorder !== 'undefined'
console.log('MediaRecorder 支持吗?', support)
this.mediaRecorder = new MediaRecorder(this.mediaStream, options);
this.chunks = [];
this.uploadChunks = [];
this.mediaRecorder.ondataavailable = (e) => {
if (e.data.size > 0) {
this.chunks.push(e.data);
this.uploadChunks.push(e.data);
}
};
this.mediaRecorder.onstop = () => this.handleRecordingStop();
this.mediaRecorder.start();
this.isRecording = true;
// 定时上传分片(每2秒)
this.uploadInterval = setInterval(() => this.uploadVideoChunk(), 2000);
this.logMessage('record_start', '开始录像');
} catch (e) {
this.onError({ msg: `录像启动失败:${e.message}` });
}
}
// 停止录像
stopRecording() {
if (!this.isRecording) return;
this.mediaRecorder.stop();
clearInterval(this.uploadInterval);
this.isRecording = false;
this.logMessage('record_stop', '停止录像');
// 上传最后分片并通知合并
setTimeout(() => {
this.uploadVideoChunk();
this.notifyBackendMerge();
}, 1000);
// 释放流
this.mediaStream.getTracks().forEach(track => track.stop());
}
// 处理录像结束
handleRecordingStop() {
const videoBlob = new Blob(this.chunks, { type: 'video/webm' });
const url = URL.createObjectURL(videoBlob)
// 把视频URL回传给Vue页面
this.saveVideoToLocal({ url })
this.logMessage('record_complete', `录像生成成功(${(videoBlob.size / 1024 / 1024).toFixed(2)}MB)`);
console.log('录像Blob大小:', videoBlob.size); // 正常应大于0
console.log('录像MIME类型:', videoBlob.type); // 应为 video/webm
// 显示视频预览
try {
const videoView = document.getElementById('videoView');
if (videoView) {
videoView.src = URL.createObjectURL(videoBlob);
console.log('视频预览URL:', videoView.src); // 应为 blob:xxx 格式
videoView.style.display = 'block';
videoView.style.border = '1px solid red';
videoView.autoplay = true;
document.getElementById('photoView').style.display = 'none';
videoView.onerror = (error) => {
console.error('录像预览失败:', error);
this.onError({ msg: `录像预览失败:${error || error.message}` });
};
}
} catch (e) {
this.onError({ msg: `录像预览失败:${e.message}` });
}
}
操作步骤:
- vue页面使用 renderjs, 然后MediaRecorder开始录制和结束录制,然后使用video播放视频。
预期结果:
- renderjs 使用录像结束之后,需要能正常播放录制后的视频。
实际结果:
- renderjs 使用录像结束之后,无法正常播放录制后的视频。
bug描述:
- uniapp 使用renderjs 和 webview两种方式在app,使用MediaRecorder 录像,结束录像之后,renderjs无法播放视频;webview 用同样的方式录像之后,能正常播放;但是普通vue页面使用webview又会全屏,nvue页面限制太多,不能用这个nvue。
- 所以有办法让renderjs 录像结束之后,正常播放视频?
更多关于uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html
1 回复
更多关于uni-app 使用renderjs 和 webview两种方式在app 开始录像和结束录制之后 renderjs方式的无法播放视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html
这个问题是RenderJS环境下MediaRecorder录制视频后无法播放的典型问题。主要原因是RenderJS与普通Webview环境在Blob URL处理机制上存在差异。
解决方案:
- 检查Blob完整性
在
handleRecordingStop方法中,添加Blob验证:
console.log('Blob chunks数量:', this.chunks.length);
console.log('Blob chunks大小:', this.chunks.map(chunk => chunk.size));
- 优化停止录制流程
修改
stopRecording方法,确保所有数据都已收集:
stopRecording() {
if (!this.isRecording) return;
// 先停止所有track
this.mediaStream.getTracks().forEach(track => track.stop());
// 再停止MediaRecorder
if (this.mediaRecorder.state !== 'inactive') {
this.mediaRecorder.stop();
}
clearInterval(this.uploadInterval);
this.isRecording = false;
}
- 使用Base64替代Blob URL RenderJS中Blob URL可能无法正确解析,改用Base64:
handleRecordingStop() {
const videoBlob = new Blob(this.chunks, { type: 'video/webm' });
// 转换为Base64
const reader = new FileReader();
reader.onload = () => {
const base64Data = reader.result;
// 传递给Vue页面
this.saveVideoToLocal({ base64: base64Data });
// 预览使用Base64
const videoView = document.getElementById('videoView');
if (videoView) {
videoView.src = base64Data;
videoView.style.display = 'block';
}
};
reader.readAsDataURL(videoBlob);
}
- 确保视频元素正确配置
// 在预览前确保video元素存在且配置正确
const videoView = document.getElementById('videoView');
if (!videoView) {
const newVideo = document.createElement('video');
newVideo.id = 'videoView';
newVideo.controls = true;
newVideo.style.width = '100%';
document.body.appendChild(newVideo);
}
- 检查MIME类型支持 RenderJS环境可能对某些MIME类型支持不完整,尝试更通用的类型:
const options = {
mimeType: 'video/mp4; codecs=avc1.42E01E,mp4a.40.2',
audioBitsPerSecond: 128000,
videoBitsPerSecond: 2500000
};

